Czytelny kod to przyjemna praca

Chlebem naszym powszednim jest kod zatem niech będzie on prosty, czytelny, po prostu smaczny. Czasem 3 minuty wystarczą aby kod był bardziej czytelny a co za tym idzie łatwiejszy do utrzymania w przyszłości. Do napisania tego wpisu natchnęła mnie poniższa linijka kodu*

[csharp]
var p = new CacheItemPolicy {
SlidingExpiration = new TimeSpan(0,0,2,0)
};
[/csharp]

Niby jest czytelnie, niby wiadomo o co chodzi… ale można lepiej:

[csharp]
var policy = new CacheItemPolicy{
SlidingExpiration = 2.Minutes();
}
[/csharp]

Czyta się lepiej. Dla uściślenia ten kawałek kodu znajduje się w funkcji

[csharp]
private void CacheViewResultForTwoMinutes(…..){

}
[/csharp]

i już wiadomo co autor miał na myśli. Nie potrzeba komentarza, ot nazwa funkcji jest wystarczającym komentarzem. Co ważne, to jest metoda prywatna więc mogę ją bezkarnie zmieniać choćby przy każdym buildzie; A wracając do meritum, Minutes to funkcja która konwertuje inta na odpowienią ilość minut zatem zaglądnijmy do środka:

[csharp]
namespace Rekord.ZOS.Lider2.Service.GatewayCommunication.Queries
{
public static class IntExtensions
{
private const int SecondsInMinute = 60;

public static int MinutesInSeconds(this int minute)
{
return minute*SecondsInMinute;
}

public static TimeSpan Minutes(this int value)
{
return TimeSpan.FromSeconds(value.MinutesInSeconds());
}
}
}
[/csharp]

Takie proste zabiegi powodują, że kod jest dużo bardziej czytelny niż początkowe new TimeSpan(0,0,2,0) od którego to się zaczęło. Prosta refaktoryzacja spowodowała, że teraz wszędzie gdzie mówimy o czasie możemy napisać 20.Minutes() i już wiadomo że chodzi o 20 mintu – bez wnikania co autor miał na myśli. Jakby ktoś kiedyś zapomniał co to minuta i ile ma sekund to też może sprawdzić 😉

A teraz najważniejsze, wszystko po to aby napisać w funkcji

[csharp]

CacheViewResultForTwoMinutes(…,…,…);

..

..

[/csharp]

zamiast powiększać funkcję zbędnymi detalami implementacyjnymi:

[csharp]

var p = new CacheItemPolicy {
SlidingExpiration = new TimeSpan(0,0,2,0)
};
MemoryCache.Default.AddOrGetExisting(key, view, p);

[/csharp]

*) tak, wiem, że można napisać TimeSpan.FromMinutes(2). Celowo nie zostało to tutaj użyte, żeby zobrazować pewien mechanizm.

Dlaczego warto pisać testy jednostkowe

Dzisiaj będzie gadka motywacyjna o pisaniu testów więc jeśli jeszcze nie piszesz, może to Ciebie w końcu przekona.

We wpisie Testowanie własnego ControllerFactory w MVC pisałem jak to zmarnowałem 6h na napisanie praktycznie jednego testu do kawałka kodu, który można napisać w 15 minut i przez dodatkowe 15 minut prze-klikać w kilku różnych przypadkach. Gdzie tu logika, gdzie tu sens. Pisząc CustomControllerFactory nie pisze się go z byle powodu, pisze się, ponieważ są potrzebne bardzo specyficzne wymagania. Pisząc kod wiemy dokładnie co robi każda linijka, wiemy po co jest każdy jeden if i dlaczego wartość trzeba pomnożyć razy 0.192 co 10te obliczenie. Jednak co się stanie z tą wiedzą za tydzień albo za miesiąc czy za rok? Na prawdę będziesz wiedzieć co to jest to wspomniane 0.192? Będziesz wiedzieć co robi flaga isLocal = false? Założę się, że 90% tego typu wiedzy wyparuje. Więc jeśli po roku przyjdzie nam napisać nową funkcjonalność lub poprawić buga, jest olbrzymia szansa, że zupełnie nieświadomie coś zepsujemy bo już nie będziemy pamiętali dlaczego coś zostało napisane tak a nie inaczej. Jeśli jednak napiszemy testy to ta wiedza jest zawarta w testach. Nawet i za 20 lat uruchamiając testy będzie można sprawdzić czy założenia są spełnione i to bez względu na to czy kod po drodze był refaktoryzowany czy nie. Niezły luksus. Jeśli to nie przekonuje Cię do testów jednostkowych to mam jeszcze jedną historię z życia wziętą:

Napisałem mechanizm wczytywania licencji w C#… z pliku tekstowego generowanego w Delphi… z testami jednostkowymi. Generalnie lodzio miodzio, wszystko działa. Do czasu aż nie okazało się, że polskie literki nie bardzo działają. Gdzieś się tablice bajtów nie zgadzały, licencja się nie validowała, ogólnie masakra. Trzeba poprawić. Wygenerowana została testowa licencja z polskimi znaczkami, która nie działała. Dopisany został nowy test z tą licencją – test nie przechodzi. Po w sumie 15 minutach, jest… ta jedna linijka kodu (ave SOLID) gdzie małe hokus pokus z encodingami i bam…. licencja działa, validuje się. Super! ale teraz trzeba będzie wygenerować nowe licencje dla starych klientów no bo nowa wersja z taką zmianą zepsuje się na starych plikach…. i tu oświecenie. Przecież dopisaliśmy nowy test z polskimi literkami, a przecież stare testy się nie zmieniły i dalej działają, czyli poprawka działa na nowe a nie psuje starego. Hura.. w 15 minut zakończone zadanie. Nie trzeba było generować iluś tam licencji, wgrać, konfigurować, prze-klikać. Testy zaoszczędziły co najmniej godzinę mojego czasu i nie wiem ile czasu wdrożeniowca. I jak tu wierzyć komuś, kto mówi, że pisanie testów kosztuje 2x tyle czasu co pisanie bez testów.

Testowanie własnego ControllerFactory w MVC

Piękno ASP.NET MVC polega na tym, że prawie wszystko można wymienić, zamienić, przetestować… tyle tylko, że Ci goście z Microsoftu uwielbiają internal-e. Wszysko co się da dają jako internal a może nawet więcej. No i tyle byłoby z testowalności, ale do rzeczy.

Piszę własny ControllerFactory ale nie zupełnie od zera. Chcę standardowej funkcjonalności ale też chcę ładować jak pluginy z luźnych dll-ek. Nic prostszego, wystarczy trochę zmodyfikować DefaultControllerFactory i jeśli standardowe GetControllerType nie znajdzie odpowiedniego kontrolera to chcę po swojemu poszukać go w osobnych assembly. PseudoControllerFactory, który realizuje taką funkcjonalność jak na rycinie poniżej:

[csharp]
public class CustomControllerFactory : DefaultControllerFactory
{

public override IController CreateController(RequestContext requestContext, string controllerName)
{
var controllerType = GetControllerType(requestContext, controllerName) ??
GetPluginControllerType(requestContext, controllerName);

return controllerType != null ? GetControllerInstance(requestContext, controllerType) : null;
}

private Type GetPluginControllerType(RequestContext requestContext, string controllerName)
{
return controller_type_from_external_assembly(controllerName);
}
}
[/csharp]

Tylko jak to to przetestować? Trzeba jakoś tak spreparować RequestContext, żeby domyślny GetControllerType zwrócił null… no i zaczynają się schody, a to „This method cannot be called during the application’s pre-start initialization stage”, a to jakiś null reference exception a to jeszcze coś innego. Ściągnąłem źródła do MVC4 ale też nic nie pomogło, bo to co bym chciał nadpisać, zamockować czy jeszcze jakoś inaczej zaczarować to internal. Tak zupełnie przy okazji dowiedziałem się jak mvc sobie cacheuje informacje o controllerach – ciekawe czy mi się to przyda.

No i nagle… EUREKA GetControllerType jest internal protected więc walnę sobie jeszcze jedną klaskę dla czytelności tym razem w testach:

[csharp]
public class CustomControllerFactoryUnderTest : CustomControllerFactory
{
protected override Type GetControllerType(RequestContext requestContext, string controllerName)
{
return null;
}
}
[/csharp]

Teraz wszystkie testy zamiast na CustomControllerFactory piszę na CustomControllerFactoryUnderTest ale za to mam pewność, że GetControllerType zwróci nulla (i to bez mocków) no i reszta testów jakoś się już potoczy. W sumie to ten internal nie taki zły (przecież mogli dać private)

*) w kwestii formalnej GetControllerType jest protected internal dzięki czemu można ją nadpisać w innym assembly.

ScriptCS i szybki prototyp z WebAPI

W poniedziałek pisałem, że nie testowałem scriptcs-sublime. To się już zmieniło. Zainstalowałem i działa. Co więcej zainstalowałem drugi plugin build-with-input a to wszystko po to aby móc do skryptu przesłać coś za pomocą klawiatury bezpośrednio z poziomu samego sublime text-a.

Instalacja:

w konsoli gita teleportuję się do C:\Users\[uzytkownik]\AppData\Roaming\Sublime Text 2\Packages i wpisujemy magiczne znaki runiczne:

git clone https://github.com/scriptcs/scriptcs-sublime.git

oraz

git clone https://github.com/eric-wieser/build-with-input.git

to pobierze nam najnowsze wersje dodatków scriptcs-sublime oraz build-with-input. Narzędzie naostrzone zatem przestrzelamy sublime text-a i piszemy:

[csharp]
Console.Write("what is your name : ");
string name = Console.ReadLine();
Console.WriteLine("Hello {0}",name);
[/csharp]

w konsoli możemy teraz zapodać Enter –> wpisać tekst –> jeszcze jeden Enter i mamy działający program na poziomie początkującym początkującym.

image

Proste, zatem przejdźmy do czegoś trochę bardziej skomplikowanego. Serwer z webapi w 34 linijkach.

Uruchomimy serwer na porcie 85 (powinien być wolny). Jeśli tak samo jak ja wyznajesz, że developer nie powinien mieć uprawnień administratora lokalnego to przydzielmy sobie przestrzeń nazw za nim będzie za późno 😉 W konsoli (z uprawnieniami admina)

netsh http add urlacl http://+:85/demo/webapi user=wszyscy

Oczywiście w zależności od potrzeb modyfikujemy port, resztę linku oraz usera, na którym chcemy pracować (http://msdn.microsoft.com/en-us/library/ms733768.aspx).

Pakiety:

Potrzebujemy również kilka pakietów. W katalogu w którym zapisujemy nasz plik csx wystarczy uruchomić

scriptcs -install scriptcs.webapi

to spowoduje pobranie wszystkiego co będzie potrzebne do webapi.

Kod:

A teraz mięso czyli potrzebujemy System.Net.Http deklarujemy swój kontroler (tutaj TestController), później własny header handler, który przyda się do dodania dodatkoowych nagłówków a to po to, żebyśmy mogli konsumować to api za pomocą ajaxa z dowolnej domeny. Ostatnie 10 linijek to stworzenie serwera i to wszystko.

[csharp]
using System.Net.Http;

public class TestController : ApiController {
public string Get() {
return "Hello world!";
}
}

public class CustomHeaderHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken)
.ContinueWith((task) =>
{
HttpResponseMessage response = task.Result;
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Methods", "GET");
response.Headers.Add("Access-Control-Allow-Headers", "X-Requested-With");
return response;
});
}
}

var webApi = Require<WebApi>();
var config = new HttpSelfHostConfiguration("http://localhost:85/demo/webapi");
config.MessageHandlers.Add(new CustomHeaderHandler());
var server = webApi.CreateServer(config);

server.OpenAsync().Wait();

Console.WriteLine("Listening…");
Console.ReadLine();
server.CloseAsync().Wait();
[/csharp]

odpalamy koda i mamy pod adresem http://localhost:85/demo/webapi serwer, który odpowiada na geta standardowym hello world.

image

wchodzimy z przeglądarki i…

image

czyli webapi odpowiedziało xml-em.

Możemy też wysłąć requesta np z webstorma (lub fiddlera) i zassać jsona:

image

A może ajaxem:

[javascript]
$.ajax({
url:’http://localhost:85/demo/webapi/test’
}).done(function(response){
alert(response);
})
[/javascript]

image

Całkiem dobry start aby napisać jakiś model backendu w webapi i szybko zacząć prototypować html-e

ScriptCS czyli C# bez ceremonii

O ScriptCS było głośno kilka miesięcy temu (bodajże w marcu) gdy pojawił się na .netowej scenie. W dużym skrócie jest to uskryptowiona wersja  C#-a. To powoduje, że jeśli chcemy zbudował/przetestować kawałek kodu, nie musimy odpalać całego Visuala. Wystarczy napisać:

[csharp]

Console.WriteLine(“hello scriptcs”)

[/csharp]

i powinno się wykonać (tak – na końcu nawet nie ma średnika).

Do wykonania powyższego będziemy potrzebowali najnowszych źródeł ScriptCS-a

https://github.com/scriptcs/scriptcs

które należy skompilować (albo przez VS albo za pomocą załączonego build.cmd – osobiście skompilowałem release w visualu i wrzuciłem do c:\scriptCS)

A teraz edytor… a jeśli ma być bez ceremonii i zbędnych ruchów to chcę łatwo uruchomić kawałek napisanego kodu. Sublime Text, którego dość często używam potrafi uruchamiać kod, ale trzeba go skonfigurować – standardowo jest przygotowany na 9 różnych języków ale próżno szukać tam scriptcs-a zatem:

Tools –> Build System –> New build system i dostajemy pusty szablon:

image

pozostaje wskazać co chcemy aby SublimeText zrobił. U mnie wygląda to tak:

[code]

{
"cmd": ["c:\\scriptcs\\scriptcs.exe", "$file"],
"encoding": "cp1252"
}

[/code]

Zapisujemy plik i od teraz w menu mamy:

image

Od teraz można za pomocą Ctrl+B uruchomić nasz eksperymentalny kod w C#

Nie trzeba pisać maina, nie trzeba pisać funkcji czy klas. Poniższe kawałki kodu spokojnie zadzaiłają.

[csharp]

Console.WriteLine("hello scriptcs")

[/csharp]

Można też używać samych funkcji

[csharp]

public void HelloWorld(string name){
Console.WriteLine("Hello {0} !", name);
}

HelloWorld("John");
HelloWorld("Mike");

[/csharp]

Nawet klasę to to łyknie Uśmiech

[csharp]

public class HelloWorld{

public void Say(string name){
Console.WriteLine("Hello {0} !", name);
}
}

new HelloWorld().Say("scriptCS")

[/csharp]

Od teraz mamy edytor, w którym można szybko i łatwo sprawdzić te kilka linijek kodu z Internetu i zobaczyć czy działają. Można również pisać całe aplikacje albo proste prototypy, zastosować znajdziesz pewnie miliony.

Na moje potrzeby jak na tą chwilę taka konfiguracja jest wystarczająca. Znalazłem również pełniejszą do pobrania tutaj: https://github.com/scriptcs/scriptcs-sublime Nie wiem czy działa, to co zbudowałem przed tym znaleziskiem na razie się sprawdza. Jeśli ktoś to sprawdzi, czekam na feedback.

Odczytywanie temperatury za pomocą LM75A i Raspberry Pi

Ostatnio opisywałem czujnik LM75A, który jest banalny do podłączenia do Raspberry Pi i który jest banalny do odczytu za pomocą prostego skryptu w pythonie. Dzisiaj wgryziemy się w kod:

Zaczniemy od tego co lubię najbardziej: KOD. Najszybciej zaczniemy wpisując w terminalu

nano temperature.py

i zaczniemy kodować (rozumiem, że i2c jest skonfigurowane):

[code language=”python”]

import smbus

sensorAddress = 0x48
i2c = smbus.SMBus(1)

print i2c.read_word_data(sensorAddress,0)

[/code]

Czyli po kolej: importujemy bibliotekę smbus (zainstalowaną wcześniej)
podajemy adres czujnika (i2cdetect –y 1 żeby sprawdzić czy mamy coś podpięte i pod jakim adresem)

tworzymy obiekt reprezentujący szynę i2c (w raspberry pi rev2 jako parametr podajemy 1, w rev1 0)

i odczytujemy temperaturę. Wychodzimy z edytora i uruchamiamy skrypt:

python temperature.py

i mamy odczyt. Banalnie prosto. 🙂

A jeśli dziwi Cię dlaczego ten odczyt jest taki dziwny to dlatego, że odczytaliśmy surową wartość w formie jakiej wypluł czujnik. To jak to jest kodowane o co oznacza pisałem ostatnio zatem kod parsujący temperaturę z LM75A:

Zatem dodajemy kawałek kodu, który parsuje wartość odczytaną i zwraca prawidłową temperaturę

[code language=”python”]
def Decode(raw):
tempA = raw & 0xFF
tempB = (raw >> 8) & 0xFF
temp = (tempA << 8) | tempB
temp = temp >> 5
return temp

def Parse(input):
signBit = input >> 10
if signBit > 0:
negativeTemperature = input
return (negativeTemperature * 0.125) – 256
return input * 0.125

raw = i2c.read_word_data(sensorAddress,0)
temp = Decode(raw)
print Parse(temp)

[/code]

czyli mamy dwie funkcje, Decode, która tak przestawia bity aby zgodnie z tym co ostatnio pisałem uzyskać prawidłową liczbę w pythonie oraz Parse, która odpowiednio przelicza to na nasze dobrze znane stopnie Andersa Celsiusa.

Po sieci krąży jeszcze jedne kod do odczytu temperatury z LM75A:

[code language=”python”]
tempA = temp & 0xFF
tempB = (temp >> 8) & 0xFF
temp = (tempA << 8) | tempB
temp = temp >> 5

r = temp >> 7
if (temp & 0x8000):
r = (~r & 0x1FF)
r = r – 1
r = -r
r = r / 2.0
return str(r)

[/code]

ma on jednak małą wadę, zaokrągla odczyt do .5 więc tracimy na rozdzielczości czujnika i z .125 robi nam się 0.5 stopnia Wprawdzie w zastosowaniach domowych i meteo nie ma to wielkiego znaczenia to jednak piszę o tym, ponieważ jedna z pierwszych moich wersji bazowała na tym kodzie i zaokrąglała własnie do .5. Teraz znalazłem czas, żeby napisać to po swojemu i mam .125

Ostatnia sprawa to spięcie całości. Potrzebujemy połączyć kość LM75A z Malinką:

image

Łączymy piny:

LM75A Raspberry PI
1 (SDA) 2 (SDA)
2 (SCL) 3 (SCL)
4 (GND) 24 (Ground)
8 (VCC) 1(3V3 Power)
5 1 (3V3 Power)
6 1 (3V3 Power)
7 1 (3V3 Power)

Piny 5 6 7 możemy połączyć dowolnie z “plusem” lub “minusem” – w ten sposób ustalamy adres jednak należy pamiętać, że piny 5, 6 i 7 MUSZĄ BYĆ POŁĄCZONE.

Miłej zabawy a w następnym odcinku serii na warsztat weźmiemy ciśnienie ale dopiero w przyszłym tygodniu.

LM75A + i2c + Raspberry Pi czyli mierzymy temperaturę

Szerszy obraz czyli tzw. przydługi wstęp

Zainteresowanie szyną i2c spowodowane było moim lenistwem. Piec w domu nie ma termostatu a rozpalając go warto wiedzieć jaka jest temperatura żeby wiedzieć kiedy go zamknąć. Rozwiązanie? Czujnik temperatury w piwnicy – na piecu, najlepiej taki który będę mógł sprawdzać za pomocą telefonu. Dodatkowo dlaczego by nie mieć czujnika temperatury w każdym pokoju i w dodatku zapisywać je aby moc później oglądać jak te temperatury się zmieniają. Dostępne na rynku rozwiązania albo nie spełniają wszystkich założeń albo są mega drogie. Pod telewizorem leży malinka wiec dlaczego jej nie zaprzęgnąć do dodatkowej pracy. Idealny materiał na pet project. Wstępne założenia są takie czujnik temperatury w piwnicy, w sypialni i salonie oraz na zewnątrz – być może temperatura przy ziemi oraz na wysokości 2 metrów czyli tak jak to mierzą meteorolodzy (btw. nie ma czegoś takiego jak temperatura w/na słońcu. Prawidłowo mierzona temperatura powietrza jest dokonywana na wysokości 2m w klatce meteorologicznej zapewniającej cień. Nie mierzymy temperatury w/na „słońcu”). Wyszło 5, być może jeszcze w pokoju dzieci i może kuchni to daje 7. Po szybkiej analizie dostępnych możliwości okazało sie ze Lm75a nadaje sie najlepiej. Na jednej szynie i2c (to ważne bo dzięki temu cześć elektroniczna jest uproszczona do minimum) można podpisać 8 termometrów. Zakres mierzonej temperatury to -50 do 150 stopni. Dla mnie idealnie. Dokładność 2stopnie. Z jednej strony masakra a z drugiej – co mnie to obchodzi, to nie jest aparatura medyczna. Się skalibruje i odpowiednie poprawki w kodzie się zrobi. W zakresie domowym i zewnętrznym czujnik jest liniowy wiec nie ma stresu a pomiar temperatury w piecu wystarczy z dokładnością 5 stopni, aktualny bimetalowy wskaźnik i tak jest mocno orientacyjny.

Zatem na warsztat idzie kostka do odczytywania temperatury czyli LM75A. Idiotycznie prosta w użyciu i obsłudze kość pozwoli łatwo uzyskać zadowalające efekty i nie powinna stanowić większego problemu nawet dla początkujących elektroników. Dokumentacja techniczna znajduje się tutaj.

lm75-elememnty

Do zmontowania będą potrzebne LM75, dostępne na allegro i w przyzwoitych sklepach elektronicznych (na powyższej rycinie to te pajączki w woreczku antystatycznym) garść kondensatoró 10nF ceramicznych oraz płytki drukowane. Te ostatnie nie są obowiązkowe bo można zmontować wszystko na pająka albo jak to teraz modniej w 3D ale na allegro można dostać gotowe płytki SO8 która ułatwi pracę. Przydatny może być również kynar jeśli chcemy mieć więcej niż 1 czujnik. Przyda się również lutownica (lepiej oporowa niż transformatorowa) oraz podstawowe umiejętności z zakresu lutowania i wąchania kalafonii.

Technikalia

Kostka ma 8 wyjść. VCC to zasilanie. Malinka może zapewnić nam 3.3 lub 5V, kość wymaga zasilania w zakresie 2.8-5.5 więc 3.3 będzie ok (później będziemy się zajmować barometrem, który jest bardziej wybredny i dlatego skorzystam z 3.3). GND to masa – lub  minus zasilania. To załatwia zasilanie. SDA i SCL to szyna danych w I2C. Ponieważ całość podpinamy do Raspberry Pi, która ma rezystory podciągające to poza połączeniem VCC GND SDA i SCL mamy w pełni funkcjonalną szynę, która nić ponad to nie potrzebuje.

image

Teraz najciekawsza część. LM75 ma ustawiany adres a ustawiamy go za pomocą zwierania A0 A1 i A2 do VCC lub do GND. I2C pozwala podpiąć równolegle do 120 urządzeń więc żeby je rozróżnić od siebie –  z którym w danej chwili chcemy rozmawiać – należy je zaadresować. Adres jest ustalany przez producenta na etapie projektowania. W przypadku LM75 adres wygląda tak:

MSB LSB
1 0 0 1 A2 A1 A0

Co ważne, A0-A2 MUSZĄ być połączone albo z VCC albo z GND. Jeśli pozostawimy je wiszące to kość będzie się dziwnie zachowywać tzn. czasem będzie odpowiadać a czasem nie. Ustawiając adresy cudeńko możemy znaleźć pod adresami od 72 (0x48) do 79 (0x4F) – sprawdzimy to za pomocą komendy i2cdetect.

Zmontowana kość u mnie wygląda tak:

photo

Jak widać mistrzostwo we władaniu lutownicą nie jest jakoś specjalnie potrzebne, ważne żeby nie poparzyć się, nie ugotować kostki i nie pozwierać za dużo…. aha i nie oblizujemy grota lutownicy.

Temperatura

Kość jest samowystarczalna w tym sensie, że po ustawieniu adresu i dostarczeniu zasilania można czytać temperaturę bez jakiejś specjalnej kalibracji czy innych magicznych obrządków. Wystarczy odczytać odpowiedni rejestr (o tym jak, będzie w następnym wpisie), który zbudowany jest tak:

M S B y t e L S B y t e
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 X X X X X

D10 to znak czyli 0 temperatura dodatnia, 1 temperatura ujemna. D9 do D0 to nasza temperatura zapisana jako wartość całkowita – ofc zapisana binarnie. XXXXX są nie używane.

Dla fanów tdd trochę mięsa czyli przypadki testowe – ot wprost z dokumentacji:

11-bit binary

szenastkowo dziesiętnie wartość temperatury
01111111000 0x3F8 1016 +127.000 °C
01111110111 0x3F7 1015 +126.875 °C
01111110001 0x3F1 1009 +126.125 °C
01111101000 0x3E8 1000 +125.000 °C
00011001000 0x0C8 200 +25.000 °C
00000000001 0x001 1 +0.125 °C
00000000000 0x000 0 0.000 °C
11111111111 0x7FF -1 −0.125 °C
11100111000 0x738 -200 −25.000 °C
11001001001 0x649 -439 −54.875 °C
11001001000 0x648 -440 −55.000 °C

z wartości dziesiętnej na prawdziwą temperaturę przechodzimy tak:

dla wartości dodatniej czyli D10 = 0

(°C) = +(Temp) × 0.125 °C.

dla wartości ujemnych czyli D10 = 1

(°C) = −(pozostała część Temp) × 0.125 °C.

Wstępnie mamy omówiony pierwszy klocek układanki. Wiadomo dlaczego i czym chcę mierzyć temperaturę. W następnej części pokażę jak to to podpiąć do malinki oraz zaglądniemy do kodu który pozwoli na odczyt temperatury.

using – papierek lakmusowy Twojej architektury

W Visual Studio wersji Ultimate są narzędzia do analizowania architektury. Jednak są ludzie, którzy zamiast wydawać pieniądze na ultimate-a wolą iść do salonu i kupić sobie auto albo dwa. Jak jednak poradzić sobie bez diagramu warstw? Wystarczy pooglądać usingi.

Single Responsibility Principle mówi, że klasa powinna robić jedną rzecz, mieć jedną odpowiedzialność. Jeśli ma jedną odpowiedzialność to nie powinna raczej grzebać we wszystkich warstwach. Wątpliwe jest aby klasa, która ma jedną odpowiedzialność musiała sięgać do bazy danych i interfejsu użytkownika i plików i logiki biznesowej i Bóg raczy wiedzieć gdzie jeszcze.

Zamiast czytać całą klasę (w wersji optymistycznej <50 linii a w wersji ekstremalnej >10k linii) wystarczy rzucić okiem na usingi. Te zazwyczaj mają mniej niż 15 linijek. Jeśli mamy dobrze ponazywane biblioteki  i katalogi (w solution) to po usingach poznasz co klasa potrzebuje (tu warto wspomnieć, że ReSharper Productivity Power Tools pozwalają automatycznie usuwać niepotrzebne usingi). Jeśli usingów jest za dużo i ze zbyt wielu warstw to wiedz, że coś jest nie tak.