<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Binary Thoughts</title>
    <description>Blog o programowaniu, procesie wytwarzania oprogramowania, platformie .NET i tematach dookoła. Zapraszam!</description>
    <link>https://www.binarythoughts.pl/</link>
    <atom:link href="https://www.binarythoughts.pl/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sun, 02 Aug 2020 03:42:10 -0500</pubDate>
    <lastBuildDate>Sun, 02 Aug 2020 03:42:10 -0500</lastBuildDate>
    <generator>Jekyll v4.1.1</generator>
    
      <item>
        <title>Pięć praktyk usprawniających Code Review</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-code-review.jpg&quot; alt=&quot;Code Review&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Zwinność polega na ciągłej poprawie. Prowadzimy retrospektywy, poprawiamy cykl życia aplikacji, przyspieszamy dostarczanie nowych wersji aplikacji, sprawiamy, że nasza praca jest bardziej przejrzysta. Wreszcie poprawiamy jakość naszego kodu.&lt;/p&gt;

&lt;p&gt;Najsłynniejszą praktyką poprawinia jakości kodu jest Code Review. Code Review jest procesem weryfikacji i ulepszania kodu. Proces przeglądania kodu ma istotny efekt uboczny - propaguje dobre rozwiązania i uczy zespół nowych technik programowania. Code Review ma wiele odmian. Możesz używać narzędzi do porównywania przyrostu kodu i współdzielenia komentarzy lub przejrzeć zmiany razem z autorem kodu i wprowadzić poprawki na żywo.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Będę się posługiwał głównie angielską nazwą Code Review - przegląd kodu i inne tłumaczenia rzadko funkcjonują w branży. Szkoda.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;pułapki-code-review&quot;&gt;Pułapki Code Review&lt;/h2&gt;

&lt;p&gt;Kiepskie przeglądy kodu wpływają negatywnie na zespół i mogą prowadzić do obniżenia jakości oprogramowania. Dlaczego? &lt;strong&gt;Code Review jest narzędziem komunikacyjnym.&lt;/strong&gt; Ludzie są podatni na emocje i popełniają błędy. Połącz kropki.&lt;/p&gt;

&lt;p&gt;Jeżeli jesteś niechlujny, kod z biegiem czasu będzie zamieniał się w spaghetti. Jeżeli jesteś zbyt szczegółowy, wpadniesz w niekończącą się spiralę odrzucania zmian, obrażania się, a w konsekwencji zepsujesz integralność zespołu. W jaki sposób unikniesz tych problemów? Oto garść porad:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ustal wasze cele przeglądów kodu i nadaj im priorytety.&lt;/li&gt;
  &lt;li&gt;Bądź dokładny.&lt;/li&gt;
  &lt;li&gt;Dawaj dobry przykład i motywuj innych.&lt;/li&gt;
  &lt;li&gt;Zautomatyzuj ile się da.&lt;/li&gt;
  &lt;li&gt;Integruj zmiany tak często, jak to tylko możliwe.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;ustal-wasze-cele-przeglądów-kodu-i-nadaj-im-priorytety&quot;&gt;Ustal wasze cele przeglądów kodu i nadaj im priorytety&lt;/h2&gt;

&lt;p&gt;Przegląd kodu nie naprawi wszystkich wad w waszym kodzie. Musicie skupić się na najistotniejszych rzeczach. Jaka jest największa wartość z Code Review? Na to pytanie nie istnieje uniwersalna odpowiedź. Jest to zależne od rodzaju projektu, cyklu życia oprogramowania i składu zespołu. Przykładowo, jeśli pracujesz nad krytycznym oprogramowaniem sieciowym, twój zespół może bardziej cenić wykrywanie podatności niż zwiększanie czytelności kodu. Gdy uporządkujecie cele, możecie położyć nacisk na ich realizację. Lista celów może również podkreślać złe praktyki Code Review, które chcecie porzucić lub rzeczy, które są automatycznie weryfikowane przez narzędzia.&lt;/p&gt;

&lt;p&gt;Porządkowanie celów możecie przeprowadzić następująco:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;wypiszcie wszystkie cele i korzyści płynące z przeglądów kodu,&lt;/li&gt;
  &lt;li&gt;wypiszcie wszystkie sytuacje, których chcecie unikać podczas Code Review,&lt;/li&gt;
  &lt;li&gt;indywidualnie oceńcie istotność każdego z celów,&lt;/li&gt;
  &lt;li&gt;zapiszcie cele w widocznym miejscu, aby każdy miał do nich łatwy dostęp.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Uporządkowana lista może wyglądać następująco:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;naprawienie wadliwej architektury,&lt;/li&gt;
  &lt;li&gt;naprawienie problemów wydajnościowych,&lt;/li&gt;
  &lt;li&gt;zweryfikowanie zmienionych API,&lt;/li&gt;
  &lt;li&gt;poprawienie czytelności kodu,&lt;/li&gt;
  &lt;li&gt;rozpowszechnienie dobrych praktyk i spójnych zasad pisania kodu,&lt;/li&gt;
  &lt;li&gt;poprawienie i uspójnienie nazw,&lt;/li&gt;
  &lt;li&gt;naprawienie błędów logiki aplikacji,&lt;/li&gt;
  &lt;li&gt;wyeliminowanie podatności,&lt;/li&gt;
  &lt;li&gt;poprawienie literówek,&lt;/li&gt;
  &lt;li&gt;poprawienie niespójności w stylu programowania,&lt;/li&gt;
  &lt;li&gt;&lt;del&gt;pośmianie się z głupot napisanych w kodzie&lt;/del&gt;,&lt;/li&gt;
  &lt;li&gt;&lt;del&gt;spędzenie czasu na czymś innym niż programowanie&lt;/del&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do oceny wartości możecie skorzystać z arkusza kalkulacyjnego. Może to przybrać taką postać:&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-code-review-goals-sheet.png&quot; alt=&quot;Przykładowy arkusz priorytetyzacji celów Code Review&quot; width=&quot;1066&quot; height=&quot;677&quot; /&gt;
&lt;figcaption&gt;Przykładowy arkusz priorytetyzacji celów Code Review&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;bądź-dokładny&quot;&gt;Bądź dokładny&lt;/h2&gt;

&lt;p&gt;Gdy znajdziesz wadę w przeglądanym kodzie lub dokumentacji, możesz napisać krótki komentarz dla autora: “napraw to”. Możesz również opisać:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Co jest nie tak z daną zmianą?&lt;/li&gt;
  &lt;li&gt;Jak zmiana oddziałowuje na całą aplikację?&lt;/li&gt;
  &lt;li&gt;W jaki sposób możecie naprawić problem?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Które podejście jest lepsze? Ogólną zasadą jest udzielenie odpowiedzi na trzy powyższe pytania. Odpowiadając na pytania, w znaczący sposób podniesiesz komfort pracy z twoimi komentarzami. Ten komfort jest bardzo ważny, szczególnie jeżeli pracujesz w rozproszonym zespole i nie możecie w dowolnym momencie porozmawiać w cztery oczy.&lt;/p&gt;

&lt;p&gt;Twoje skupienie jest ograniczone. Długie sesje przeglądania cudzych zmian sprawią, że będziesz mniej dokładny. Mógłbyś zapytać: ile linii kodu jestem w stanie przejrzeć w ciągu jednego dnia? Nie ma na to dobrej odpowiedzi. Projekt jest podzielony na funkcje, klasy, moduły, subaplikacje. Fragmenty projektu mają różną złożoność. Członkowie zespołu mają różne doświadczenia i w różny sposób się z nimi kooperuje.&lt;/p&gt;

&lt;p&gt;Możecie ustalić limit przejglądanych linii kodu na dzień, jednakże utrudni to zobaczenie pełnego obrazu zmian. Przejrzyjcie cele, które ustaliliście i podejmijcie decyzję, czy limit ma zastosowanie w waszym projekcie. Jeżeli wielkość zmian przyprawia cię o zawroty głowy, spróbuj skupić się na pojedyńczym celu z góry listy, ukończ go i przejdź do kolejnego. Jeśli używacie mechanizmu &lt;em&gt;Pull Request&lt;/em&gt;, może warto podzielić zmiany na kilka PRów?&lt;/p&gt;

&lt;h2 id=&quot;dawaj-dobry-przykład-i-motywuj-innych&quot;&gt;Dawaj dobry przykład i motywuj innych&lt;/h2&gt;

&lt;p&gt;Przeglądanie kodu jest procesem komunikacyjnym. Ty komunikujesz potencjalne wady w kodzie i dokumentacji. Twój współpracownik komunikuje, czy zgadza się twoim punktem widzenia. Brzmi prosto? Niestety, Code Review może się zrobić bardzo nieprzyjemne, gdy emocje wezmą nad wami górę. Z emocjami związanych jest kilka problemów.&lt;/p&gt;

&lt;p&gt;Po pierwsze, deweloperzy są często przywiązani do swoich metod pracy, rozwiązań i wprowadzonych zmian. Na pewno kojarzysz poniższy obrazek.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/post-code-review-code-ownership.png&quot; alt=&quot;Przywiązanie do własnego kodu&quot; width=&quot;976&quot; height=&quot;782&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Jeżeli zaczniesz zmuszać współpracowników do wprowadzenia twoich poprawek, koledzy nastawią się defensywnie i w niedługim czasie będziecie się kłócili o marginalne rzeczy, np. spacje kontra tabulacje. Ty wiesz, że masz rację. Twój kolega wie, że ma rację. Oboje się mylicie. Jaki jest skutek takiej kłótni? Na pewno zmarnowany czas i większe napięcie między wami.&lt;/p&gt;

&lt;p&gt;Drugim problemem jest fakt, że deweloperzy przeglądają kod jakby byli kompilatorami. Próbujesz znaleźć wszystkie potencjalne błędy i czekasz, aż autor zmian je naprawi. Pracując w ten sposób, będziesz czepiał się drobnych błędów. Nie zauważysz za to istotnych problemów, które uderzą ciebie i resztę zespołu po czasie.&lt;/p&gt;

&lt;p&gt;Kolejny problem jest również związany z trybem żywego kompilatora. Jeżeli autor zmian nie wprowadzi wszystkich proponowanych przez ciebie poprawek, ty nie zaakceptujesz zmian. Komentarze w Code Review powinny sprawiać, że produkt staje się lepszy. Produkt staje się lepszy, jeśli zespół staje się lepszy. Nie naciskaj na kolegów zbyt mocno podczas proponowania alternatywnych rozwiązań. Jeśli będziesz za bardzo naciskał, szybko okaże się, że twoje komentarze są traktowane jako zbyt rygorystyczne i ignorowane. Jeśli tak się stanie, zmarnowałeś tylko swój swój czas.&lt;/p&gt;

&lt;p&gt;Produktywne przeglądanie kodu oznacza usprawnianie procesu krok po kroku. Chcesz lepszych wrażeń podczas przeglądania kodu lub dostawania lepszego feedbacku do twojego kodu? Zacznij od poprawienia swojego podejścia. Jeżeli będziesz trzymał się poniższych zasad, będziesz szerzył pozytywne i profesjonalne podejście w swoim zespole. Zasady są proste:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Nie traktuj uwag do kodu osobiście.&lt;/li&gt;
  &lt;li&gt;Komplementuj dobre rozwiązania.&lt;/li&gt;
  &lt;li&gt;Stopniowo podnoś umiejętności i wiedzę swoich współpracowników.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;zautomatyzuj-ile-się-da&quot;&gt;Zautomatyzuj ile się da&lt;/h2&gt;

&lt;p&gt;Code Review wymaga bardzo dużego zaangażowania. Na szczęście istnieje wiele narzędzi, które ściągną część pracy z twoich barków. Wiele problemów z kodem zostanie wykrytych dzięki zastosowaniu analizatorów kodu. Niektóre analizatory pokazują niespójności w stylu kodu. Inne wykryją potencjalne podatności lub problemy wydajnościowe. Jeszcze inne znajdą literówki i słowa zabronione w dokumentacji twojego publicznego API.&lt;/p&gt;

&lt;p&gt;Jeśli szukasz narzędzi dla stosu .NET/JavaScript, mam dla ciebie kilka propozycji:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;StyleCop.Analyzers&lt;/em&gt; - narzędzie dla kodu C#, które wyszukuje problemów ze stylem kodu,&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;ESLint&lt;/em&gt; - narzędzie dla kodu JavaScript, które określa dopuszczalny styl kodu (np. wymusza brak średnika na końcu linii),&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;SonarQube&lt;/em&gt; - narzędzie ciągłej integracji wyszukujące popularne problemy z kodem (np. duplikacja, podatności) w różnych językach,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/roslyn/wiki/Getting-Started-Writing-a-Custom-Analyzer-&amp;amp;-Code-Fix&quot;&gt;własny analizator .NET&lt;/a&gt; - możesz napisać własny analizator kodu .NET oparty o kompilator &lt;em&gt;Roslyn&lt;/em&gt;, który będzie działał tak, jak &lt;em&gt;StyleCop.Analyzers&lt;/em&gt;, ale będzie skupiał się na twoich specyficznych potrzebach.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pamiętaj, że automatyzacja jest ma większą wartość, jeśli działa tak samo na każdej maszynie deweloperskiej oraz na serwerze CI.&lt;/p&gt;

&lt;h2 id=&quot;integruj-zmiany-tak-często-jak-to-tylko-możliwe&quot;&gt;Integruj zmiany tak często, jak to tylko możliwe&lt;/h2&gt;

&lt;p&gt;Jednym z większych problemów Code Review są zbyt duże zmiany do przejrzenia. Przeglądanie dwóch tygodni cudzej pracy nigdy nie należy do najprzyjemniejszych. Rozwiązanie na zbyt duże Pull Requesty jest proste - wystawiaj je częściej. Możesz wydzielić ze swojego zadania fragmenty, których zaimplementowanie nie wpłynie na działanie aplikacji (np. backend do strony, która jeszcze nie jest zrobiona). Możesz również używać &lt;em&gt;feature toggle&lt;/em&gt; - zostawiasz daną funkcję aplikacji wyłączoną, dopóki nie będzie w pełni wykonana.&lt;/p&gt;

&lt;p&gt;Integrowanie fragmentów zmian wymaga większego rygoru pracy. Programy mają to do siebie, że bardzo łatwo się psują od wprowadzanych zmian. Częste integrowanie zmian w kodzie będzie skuteczne, jeżeli będziesz posiadać dobre testy automatyczne. Najczęściej potrzebne są testy o różnym poziomie granularności - testy jednostkowe, testy integracyjne, testy akceptacyjne, czasem różnież testy &lt;em&gt;end-to-end&lt;/em&gt;. Twój &lt;em&gt;mainline&lt;/em&gt; (np. branch &lt;em&gt;develop&lt;/em&gt;) powinien być utrzymywany w stanie gotowości do wydania. Nie oznacza to, że nie może zawierać kodu z zadań, które nie zostały zaakceptowane. Po prostu ten kod powinien być wykonywany na produkcji przed ukończeniem całości.&lt;/p&gt;

&lt;h2 id=&quot;wnioski&quot;&gt;Wnioski&lt;/h2&gt;

&lt;p&gt;Istnieje wiele technik usprawniających Code Review. Pamiętaj jednak, że proces przeglądania kodu musi być dopasowany do potrzeb twojego produktu i do twojego zespołu. Nie zapominaj również, że Code Review jest procesem komunikacyjnym - im lepiej wyjaśnisz swój punkt widzenia, tym więcej wartości wyniknie z CR. W celu zmniejszenia zakresu konwersacji, zautomatyzuj weryfikację powtarzalnych rzeczy, na które się zgodziliście całym zespołem deweloperskim.&lt;/p&gt;

</description>
        <pubDate>Tue, 04 Sep 2018 07:30:00 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2018/09/code-review/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2018/09/code-review/</guid>
        
        <category>teamwork</category>
        
        
      </item>
    
      <item>
        <title>Efektywny Daily Scrum - nie marnuj kwadransu ze swojego poranka</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-daily-scrum.jpg&quot; alt=&quot;Moscow Rugby team&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Daily Scrum jest jednym z obowiązkowych wydarzeń w Scrumie. Jednocześnie to spotkanie jest najczęściej wykonywane ze względu na obowiązek - bez zrozumienia celu. Czy znasz poniższy scenariusz?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Wchodzisz rano do biura. Zaspany, z nienawiścią w oczach patrzysz na nich - ludzie z zespołu. Wybija godzina zero - stajecie w kółku i składacie raport. Marian nie zrobił tego, co zaplanował wczoraj, ale znalazł śmieszny fragment kodu. Zbyszek zapłakał nad swoim losem przy współpracy z innym działem. Janusz scrolluje kwejka na telefonie. Dalej nie pamiętasz, bo odpłynąłeś. Wybudzony przez Scrum Mastera bełkoczesz coś o tym, że będziesz kontynuować to, co wczoraj. Wszyscy kiwają głową. Kończycie po 20 minutach, rozchodzicie się do biurek. Nikt nie wie, co przyniesie następny dzień.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Jeżeli twoje wizyty w pracy wyglądają w ten sposób, to znak, że Ty i twoi koledzy marnujecie każdego dnia część swojego życia. &lt;strong&gt;Zobacz, jak przestać marnować cenny czas podczas Daily Scrum - zmień to spotkanie w najważniejszy punkt swojego dnia.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;daily-scrum-vs-standup&quot;&gt;Daily Scrum vs Standup&lt;/h2&gt;

&lt;p&gt;Z jakiegoś powodu przyjęło się, że poranne spotkania nazywa się standupem. Każdy ma stać, bo pomaga to przyspieszyć spotkanie. Standup nie jest praktyką scruma - wywodzi się z metodyki Extreme Programming. Scrumowym odpowiednikiem jest Daily Scrum. Forma tego spotkania jest podobna. Nie ma jednak wymogu stania. Argumentowanie, że spotkanie powinno się odbywać na stojąco to próba wykonania magicznej sztuczki naprawiającej niedociągnięcia.&lt;/p&gt;

&lt;h2 id=&quot;do-czego-służy-daily-scrum&quot;&gt;Do czego służy Daily Scrum?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Daily Scrum służy do ustalenia strategii na następne 24 godziny. Wydarzenie to daje możliwość inspekcji wykonanego postępu i adaptacji planu. Planowanie jednej doby pozwala na uszycie dużo dokładniejszego planu niż planowanie całego sprintu.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Spotkanie wymaga większej szczegółowości, a więc również większego zaangażowania. Każdy uczestnik musi pozostać przytomny przez całość spotkania. Z tego powodu spotkanie musi trwać &lt;strong&gt;maksymalnie 15 minut&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Daily Scrum wymaga skupienia, co wymusza rygorystyczne podejście.&lt;/strong&gt; Spotkanie musi zawsze odbywać się o jednej porze. Najlepiej jest to zrobić na początku dnia, jednak nie jest to wymóg. Bardzo ważne jest pilnowanie godziny rozpoczęcia. Spóźnianie się powoduje marnowanie czasu reszty zespołu. Jeśli nie zdążyłeś na początek Daily, to straciłeś ty i straciła reszta zespołu. Nie pogarszaj stanu. Nie przeszkadzaj innym i nie snuj opowieści o spóźnionym tramwaju. Włącz się do planowania rzeczy, które nie były jeszcze omawiane.&lt;/p&gt;

&lt;h2 id=&quot;kto-powinien-uczestniczyć-w-daily&quot;&gt;Kto powinien uczestniczyć w Daily&lt;/h2&gt;

&lt;p&gt;Daily Scrum jest dla zespołu deweloperskiego. Nie, nie dla waszego przełożonego, Scrum Mastera, właściciela produktu czy Pana Kanapki. To wy musicie zadbać o utrzymanie poprawnej formy.&lt;/p&gt;

&lt;p&gt;Obecność zespołu deweloperskiego jest obowiązkowa. Scrum Master ma jedynie zapewnić, że spotkanie się odbędzie. Pozostali aktorzy - właściciel produktu, klient, szef etc. mogą być gośćmi. To od was zależy, czy pozwolicie im na wzięcie udziału w spotkaniu.&lt;/p&gt;

&lt;h2 id=&quot;zmień-swoje-nawyki&quot;&gt;Zmień swoje nawyki&lt;/h2&gt;

&lt;p&gt;Efektywne przeprowadzanie Daily zacznij od zmiany swoich nawyków:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;przygotuj się do daily,&lt;/li&gt;
  &lt;li&gt;słuchaj innych,&lt;/li&gt;
  &lt;li&gt;mów zwięźle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gdy poprawisz swoje nastawienie, część członków zespołu deweloperskiego zacznie Cię naśladować. Pozostałych będziesz musiał przekonać do nowego podejścia. Nie możesz tego wymusić - &lt;strong&gt;wszyscy musicie rozumieć wartość i cel spotkania&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;przygotuj-się-do-daily&quot;&gt;Przygotuj się do daily&lt;/h3&gt;

&lt;p&gt;Spotkanie będzie tym efektywniejsze, im lepiej będziecie do niego przygotowani. Poświęć pięć minut przed spotkaniem. &lt;strong&gt;Zbierz aktualny obraz sprintu.&lt;/strong&gt; Sprawdź jeszcze raz nad czym aktualnie pracujecie. Zobacz w jakim stanie są wszystkie zadania. Przeczytaj komentarze, jeżeli istnieją. Dzięki temu będziesz znał kontekst tego, o czym mówią koledzy. Lepiej doradzisz lub pomożesz w spełnieniu celu. Wykryj potencjalne zatory - środowiska testowe i czas ludzi spoza zespołu są ograniczonymi zasobami. &lt;strong&gt;Przemyśl, co chcesz powiedzieć o zadaniach, które wykonujesz.&lt;/strong&gt; Podsumuj stan w porównaniu do poprzedniej doby. Zbierz istotne problemy, z którymi zespół może Ci pomóc. Zaplanuj następny krok.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.scrumguides.org/docs/scrumguide/v2017/2017-Scrum-Guide-Polish.pdf&quot; target=&quot;_blank&quot;&gt;Scrum Guide&lt;/a&gt; definiuje trzy pomocnicze pytania, które pomogą ci w przygotowaniu się.&lt;/p&gt;

&lt;blockquote&gt;
    Przebieg spotkania jest ustalany przez Zespół Deweloperski. Może ono być przeprowadzane na wiele sposobów, jeśli tylko pozostaje poświęcone postępom prac w kierunku osiągnięcia Celu Sprintu. Niektóre Zespoły Deweloperskie wykorzystują pytania, inne prowadzą dyskusje. Oto przykład pytań, które mogą być wykorzystywane podczas tego spotkania:

    &lt;ul&gt;
        &lt;li&gt;Co zrobiłem wczoraj, co pomogło Zespołowi Deweloperskiemu przybliżyć się do
        osiągnięcia Celu Sprintu?&lt;/li&gt;
        &lt;li&gt;Co zrobię dzisiaj, co pomoże Zespołowi Deweloperskiemu przybliżyć się do osiągnięcia Celu Sprintu?&lt;/li&gt;
        &lt;li&gt;Czy widzę jakiekolwiek przeszkody mogące uniemożliwić mi lub Zespołowi Deweloperskiemu osiągnięcie Celu Sprintu?&lt;/li&gt;
    &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Przykładowe pytania mają pomóc ci w uporządkowaniu wypowiedzi. Nie musisz, a nawet nie powinieneś mechanicznie udzielać na nie odpowiedzi.&lt;/p&gt;

&lt;h3 id=&quot;słuchaj-innych&quot;&gt;Słuchaj innych&lt;/h3&gt;

&lt;p&gt;Celem spotkania jest ułożenie planu. Dokonanie tego jest możliwe tylko wtedy, jesli słuchasz innych. &lt;strong&gt;Twoim głównym zadaniem na Daily jest słuchanie.&lt;/strong&gt; Telefon zostaw przy biurku. Tematy pozasprintowe odłóż na dalszy plan. Twoim głównym zadaniem jest słuchanie. Słuchanie jest twoim głównym zadaniem. Zadaniem twoim jest słuchanie. Powtórz sobie to jeszcze kilka razy. Byle nie na Daily, bo na Daily twoim głównym zadaniem jest słuchanie. Jutro kolega może wpaść pod autobus albo pojechać na wakacje. Bądź na to gotowy. Zapamiętaj, czym się zajmuje.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Słuchanie pozwoli ci na zaktualizowanie swojej wiedzy o aktualnym stanie sprintu oraz wykrycie nieprawidłowości i rozbieżności.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;mów-tak-zwięźle-jak-to-możliwe-ale-nie-zbyt-zwięźle&quot;&gt;Mów tak zwięźle, jak to możliwe (ale nie zbyt zwięźle)&lt;/h3&gt;

&lt;p&gt;Zasadniczo powinieneś się odzywać tylko w trzech sytuacjach, gdy:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;wykryjesz poważną nieprawidłowość,&lt;/li&gt;
  &lt;li&gt;jesteś w stanie pomóc w rozwiązaniu problemu,&lt;/li&gt;
  &lt;li&gt;omawiacie zadanie, nad którym pracujesz.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Przejęzyczenie się nie jest proważną nieprawidłowością. Poważną nieprawidłowością jest:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;niespójność w jakiejkolwiek postaci,&lt;/li&gt;
  &lt;li&gt;oddalenie się lub brak dążenia od celu sprintu,&lt;/li&gt;
  &lt;li&gt;nieuzgodnione obniżenie jakości projektu,&lt;/li&gt;
  &lt;li&gt;naruszanie formy Daily Scruma.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Niespójność występuje, gdy zadanie lub komentarze mówią coś innego, a poprzedniego dnia plan zupełnie różnił się od aktualnie omawianego stanu. Oddalenie się od celu sprintu pojawia się przy refaktoryzowaniu czegoś “przy okazji” i prowadzeniu nieudokumentowanych prac. Obniżenie jakości projektu może być cichym zaciąganiem długu technicznego, brakiem testów, brakiem dokumentacji lub nieprawidłowym zaprojektowaniem funkcji systemu. &lt;strong&gt;Jeśli ktoś dąży do wysadzenia sprintu w powietrze - reaguj, zanim będzie za późno!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jeśli już musisz coś powiedzieć - zastanów się, czy sam byś chciał to usłyszeć. Nie marnuj czasu innych.&lt;/strong&gt; Twoja wczorajsza impreza i alkoholowy oddech powodują dekoncentrację. Daruj sobie opowiadanie o tym. Nie opowiadaj też o drobnicy. To, że wczoraj przez pół godziny nie umiałeś napisać kompilującego się kodu, nie interesuje nikogo poza tobą.&lt;/p&gt;

&lt;p&gt;Jeśli rzecz nie dotyczy tylko ciebie, mów w liczbie mnogiej - &lt;em&gt;mamy&lt;/em&gt; problem, &lt;em&gt;zrobiliśmy&lt;/em&gt; postęp, powinni &lt;em&gt;nas&lt;/em&gt; za to wywalić. Jesteście zespołem, nie działacie osobno.&lt;/p&gt;

&lt;h2 id=&quot;jak-przeprowadzić-daily-scrum&quot;&gt;Jak przeprowadzić Daily Scrum?&lt;/h2&gt;

&lt;p&gt;Ustalcie stałe miejsce i czas spotkania. Unikniecie w ten sposób niepotrzebnych pytań “Gdzie?” i “O której?”. Do efektywnego przeprowadzenia Daily Scruma musicie wybrać miejsce, w którym nikt wam nie będzie przeszkadzał. Jeżeli nieproszeni goście was prześladują, zamknij drzwi na klucz. Kwadrans nikogo nie zbawi, a twojemu zespołowi da spokój i izolację. Zamiast mówić kolejno o waszym prywatnym stanie prac, przejdźcie przez zadania. Przechodzenie po zadaniach sprawdza się dużo lepiej niż przechodzenie po ludziach - skupiacie się na celu sprintu i dostarczaniu wartości jako zespół. Zacznijcie od zadań najbliżej ukończenia - domknięcie aktualnych tematów jest ważniejsze od otwierania nowych.&lt;/p&gt;

&lt;p&gt;Utrzymanie się w ramach czasowych jest bardzo istotne. Kwadrans to wbrew pozorom bardzo dużo czasu. Jeżeli omówiliście wszystko w mniej niż 15 minut - świetnie. Jeżeli zbliżacie się do końca kwadransu i jesteście dalej w połowie - delikatnie pospiesz innych.&lt;/p&gt;

&lt;h2 id=&quot;do-czego-prowadzi-naruszanie-formy-daily-scruma&quot;&gt;Do czego prowadzi naruszanie formy Daily Scruma?&lt;/h2&gt;

&lt;p&gt;Jeżeli przychodzisz na daily scrum spóźniony, nieprzygotowany i opowiadasz o rzeczach niezwiązanych z realizacją celu sprintu, prowadzisz do zmniejszenia motywacji zespołu i wiary w sensowność tego spotkania. Taki sam efekt odniesiesz ignorując innych i przerywając im bez powodu. Konsekwencją powyższych zachowań jest trudność w połączeniu zadań, przejmowania pracy innych programistów oraz tworzeniu poprawnie zintegrowanego produktu. W efekcie w oprogramowaniu pojawiają się błędy, a klient staje się marudny. Nikt nie chce mieć marudnego klienta.&lt;/p&gt;

&lt;h2 id=&quot;podsumowanie&quot;&gt;Podsumowanie&lt;/h2&gt;

&lt;p&gt;Jesteś zmęczony bezsensownym spotkaniem, które zmusza Cię do stania w kółku i spowiadaniu się na głos przed samym sobą? Zacznij od zrozumienia celu Daily Scruma. Przed każdym Daily poświęć pięć minut na przygotowanie się. Przygotowanie się pozwoli Ci lepiej wysłuchać resztę zespołu. Gdy będziesz mówił, sformułuj wypowiedź tak, żeby dawała zespołowi wartość. Pamiętaj, że najlepsze efekty daje zarażanie innych dobrym przykładem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Czy Twój zespół praktykuje Daily Scrumy lub Standupy? Jakie reguły stosujecie? Podziel się w komentarzu.&lt;/strong&gt;&lt;/p&gt;

</description>
        <pubDate>Mon, 16 Jul 2018 03:00:00 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2018/07/efektywny-daily-scrum/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2018/07/efektywny-daily-scrum/</guid>
        
        <category>teamwork</category>
        
        <category>agile</category>
        
        <category>scrum</category>
        
        <category>dailyScrum</category>
        
        
      </item>
    
      <item>
        <title>Jak wygląda i dlaczego warto mieć zwinny zespół?</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-agile-team.jpg&quot; alt=&quot;Agile team&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Zespół to grupa fachowców mająca wspólny cel. Jakie cechy sprawiają, że zespół pracuje wydajniej, a jego członkowie spełniają się zawodowo?&lt;/p&gt;

&lt;p&gt;Ludzie są zwierzętami stadnymi. Potrzebują wzajemnej aprobaty oraz odnoszenia wspólnych zwycięstw. Żeby odnosić zwycięstwa, musimy być przygotowani na nowe sytuacje, np. skierowanie produktu do nowej grupy użytkowników. Zespół zawsze gotowy na nowe sytuacje jest zespołem zwinnym (&lt;em&gt;agile team&lt;/em&gt;). Zwinny zespół lepiej radzi sobie w zmieniającej się rzeczywistości - rzeczywistości, która nas otacza.&lt;/p&gt;

&lt;p&gt;Zwinny zespół posiada co najmniej trzy cechy:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;współdzieli cel, sukcesy i porażki,&lt;/li&gt;
  &lt;li&gt;organizuje swoją pracę samodzielnie,&lt;/li&gt;
  &lt;li&gt;amortyzuje braki w składzie i zmiany personalne.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;wspólny-cel-wspólne-sukcesy-wspólne-porażki&quot;&gt;Wspólny cel, wspólne sukcesy, wspólne porażki&lt;/h2&gt;

&lt;p&gt;Podstawową cechą jakiegokolwiek zespołu jest posiadanie wspólnego celu. &lt;strong&gt;Cel jest kompasem projektu - określa dokąd idziecie.&lt;/strong&gt; Posiadając cel, możecie dostosowywać zakres projektu, czas jego trwania lub jakość wykonania. Bez wspólnego celu podejmujecie losowe decyzje bez solidnych podstaw.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Każdy sukces zespołu i każda porażka jest waszym wspólnym mianownikiem.&lt;/strong&gt; Żaden sukces nie jest indywidualny. Tak samo żadna porażka. Nie ukończyłeś zadania - ukończyliście je wspólnie. To nie kolega Zbyszek dostarczył klientowi zbugowaną fukcję - wszyscy daliście ciała. Każdy z was miał okazję sprawdzić kod i porozmawiać o problemach, więc nie szukajcie kozła ofiarnego. Jeżeli nie mieliście okazji - macie wspólny problem z kooperacją.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jeżeli udało się wam sprostać trudnemu zadaniu, celebrujcie to.&lt;/strong&gt; Wspólne wyjście po pracy na kilka głębszych na pewno skończy się historią opowiadaną (w różnych wersjach) przez następne kilka miesięcy. Tak właśnie powstają zgrane zespoły. &lt;strong&gt;Gdy nie wszystko poszło po waszej myśli, zastanówcie się wspólnie nad przyczynami.&lt;/strong&gt; Co pięć głów to nie jedna. Gdy uda wam się zdefiniować przyczyny porażki, określcie akcje do podjęcia. W ten sposób nie sparzycie się drugi raz na tym samym.&lt;/p&gt;

&lt;h2 id=&quot;samodzielna-organizacja-pracy&quot;&gt;Samodzielna organizacja pracy&lt;/h2&gt;

&lt;p&gt;Podążanie za pierwotnym planem rzadko kończy się dotarciem do celu. Im więcej czynników zewnętrznych wpływa na waszą pracę, tym większa szansa, że oddalicie się od osiągnięcia celu. Dlatego kluczowe jest reagowanie na zmiany zaraz po ich wykryciu, zanim ich skutki się zbyt rozrosną.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zamiast czekać, aż ktoś zauważy i naprawi problem - zrób to sam.&lt;/strong&gt; Opowiedz wszystkim o sytuacji, zaproponuj rozwiązanie, nakłoń ludzi do wyrażenia swojej opinii i wprowadź zmiany, jeżeli wszyscy tego  chcecie. &lt;strong&gt;Podejście samodzielnego reagowania na zmiany nazywa się &lt;em&gt;podejściem proaktywnym&lt;/em&gt;&lt;/strong&gt;. Po przeciwnej stronie mamy &lt;em&gt;podejście reaktywne&lt;/em&gt; - bierne oczekiwanie na bodziec, np. decyzję przełożonego.&lt;/p&gt;

&lt;p&gt;Podejście proaktywne ma kilka zalet:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;krócej czekasz na dostosowanie się zespołu lub produktu do sytuacji,&lt;/li&gt;
  &lt;li&gt;rozwiązując problem bezpośrednio u jego źródła, rozwiązujesz go dużo lepiej,&lt;/li&gt;
  &lt;li&gt;w zespole nie powstają napięcia związane z trwaniem w demotywującej sytuacji,&lt;/li&gt;
  &lt;li&gt;zarażasz zespół swoim podejściem, przez co wszyscy działacie coraz efektywniej.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Przykłady podejścia proaktywnego:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Widzisz, że infrastruktura projektu jest ciężka w zrozumieniu i droga w utrzymaniu. Słyszałeś już kilka razy podobne opinie członków zespołu i interesariuszy. Przygotowujesz kilka sposobów na usprawnienie infrastruktury - zaczynasz od najtańszych we wprowadzeniu i dających największe rezultaty. Określasz konsekwencje pozostania w obecnym stanie oraz konsekwencje poszczególnych rozwiązań. &lt;strong&gt;Rozmawiasz o nich z zespołem deweloperskim, przełożonym, klientem. Wspólnie ustalacie które działania chcecie podjąć w pierwszej kolejności.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;W zespole znajduje się &lt;em&gt;czarna owca&lt;/em&gt; - osoba, która torpeduje prace zespołu i nie angażuje się w dostarczanie wartości do projektu. Człowiek jest nowy w zespole i nikt nie chce na niego naciskać. Widzisz jednak, że rośnie napięcie wśród pozostałej części zespołu. Na najbliższej retrospektywie mówisz otwarcie o sytuacji i pytasz świeżaka, w jaki sposób reszta zespołu może mu pomóc. &lt;strong&gt;Szukasz rozwiązania, które zadowoli wszystkich - takie rozwiązanie bardzo często istnieje. Jeżeli jednak go nie ma, a &lt;em&gt;czarna owca&lt;/em&gt; dalej psuje owoce waszej pracy, mówisz o całej sytuacji przełożonemu i wymagasz od niego podjęcia działań.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jeżeli nie działasz proaktywnie, to działasz reaktywnie. Podchodząc biernie do problemów możesz spóźnić się z podjęciem akcji. Produkt przestanie pasować do rynku. Koszt utrzymania infrastruktury sprawi, że zarząd zamknie projekt. Czarna owca doprowadzi do fali zwolnień. &lt;strong&gt;W podejściu proaktywnym to ty kontrolujesz sytuację. W podejściu reaktywnym to sytuacja kontroluje ciebie.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;projekt---wspólna-własność-całego-zespołu&quot;&gt;Projekt - wspólna własność całego zespołu&lt;/h2&gt;

&lt;p&gt;Projekt jest waszą wspólną własnością. Cały kod i dokumentacja jest waszą wspólną własnością. Zadania i ich opisy są waszą wspólną włanością. Wszystkie artefakty wytarzane w projekcie (kod, dokumentacja, zadania, pomysły etc.) przechodzą przez kilka par rąk, zanim zostaną wdrożone. &lt;strong&gt;Nic nie jest dziełem pracy jednej osoby.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Wpólna własność projektu oznacza:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;mniej nietrafionych pomysłów do zrealizowania,&lt;/li&gt;
  &lt;li&gt;większe zrozumienie celu,&lt;/li&gt;
  &lt;li&gt;lepiej doprecyzowane wymagania,&lt;/li&gt;
  &lt;li&gt;większa odporność zespołu na &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Bus_factor&quot; target=&quot;_blank&quot;&gt;bus factor&lt;/a&gt;&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;wspólny-kod&quot;&gt;Wspólny kod&lt;/h3&gt;

&lt;p&gt;Aby kod był wspólną własnością całego zespołu, konieczne jest zrozumienie wymagań zadania oraz co najmniej wykonanie przeglądu kodu (&lt;em&gt;code review&lt;/em&gt;). Programujecie w parach? Tym lepiej.&lt;/p&gt;

&lt;p&gt;Jeżeli nie będziecie się wymieniać obszarami projektu i przeglądać kodu kolegów, bardzo szybko się okaże, że wytworzyliście &lt;em&gt;silosy kompetencyjne&lt;/em&gt;. Oznacza to tyle, że jedna dziedzina projektu (lub fragment kodu) jest rozumiany i utrzymywany tylko przez jedną osobę. Takie podejście jest tykającą bombą. Eksploduje ona w momencie, gdy zabraknie &lt;em&gt;eksperta kompetencyjnego&lt;/em&gt; - na przykład odejdzie z zespołu. Jeszcze gorzej będzie gdy okaże się, że pozostawiony fragment systemu jest kiepskiej jakości, niezrozumiały i nie nadaje się do utrzymania.&lt;/p&gt;

&lt;p&gt;Wpólny kod oznacza również, że ludzie spoza zespołu deweloperskiego mogą go modyfikować. Mając jasno określone zasady akceptacji zadania, nic nie stoi na przeszkodzie, żeby właściciel produktu lub &lt;em&gt;scrum master&lt;/em&gt; wprowadził zmiany. Programiści nie mają monopolu na programowanie - są do tego jedynie najlepiej przygotowani.&lt;/p&gt;

&lt;h3 id=&quot;wspólne-zadania&quot;&gt;Wspólne zadania&lt;/h3&gt;

&lt;p&gt;Zadania, które implementujesz jako programista są waszą wspólną własnością. Każdy w zespole powinien wiedzieć jaki jest cel zadania - naczęściej wyraża się to za pomocą opowieści użytkownika (&lt;em&gt;user story&lt;/em&gt;, &lt;em&gt;US&lt;/em&gt;). Zadanie powinno określać wymagania potrzebne do uznania go za skończone - np. wyrażone w formie kryterów akceptacji (&lt;em&gt;acceptance criteria&lt;/em&gt;, &lt;em&gt;AC&lt;/em&gt;). &lt;strong&gt;Każdy członek zespołu powinien mieć możliwość negocjowania zmian w zadaniu - również w trakcie trwania sprintu. Negocjując zadania jesteście w stanie dostarczyć więcej przydatnych rzeczy.&lt;/strong&gt; Jeżeli spełnicie cel, możecie uprościć szczegóły. Przykładem uproszczenia szczegółów jest zrealizowanie dużo łatwiejszej implementacji, która zmienia jedynie mało istotne kryteria akceptacji. Każda zmiana musi być uzgodniona z właścicielem produktu (&lt;em&gt;product owner&lt;/em&gt;, &lt;em&gt;PO&lt;/em&gt;) oraz zaakceptowana przez resztę zespołu. Właściciel produktu nie ma monopolu na tworzenie i spisywanie zadań - jest do tego jedynie najlepiej przygotowany.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Właściciel produktu ma za to monopol na ustalanie priorytetów, o czym warto pamiętać.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;fluktuacja-członków-zespołu&quot;&gt;Fluktuacja członków zespołu&lt;/h2&gt;

&lt;p&gt;Projekty wymagające utrzymania spotykają się ze zmianami kadrowymi. Każda zmiana w składzie twojego zespołu spowoduje zaburzenia produktywności i powstanie nowych wyzwań. Nowe osoby trzeba przygotować do bycia członkiem zespołu - nauczyć kultury pracy i pokazać cel. Po starych współpracownikach trzeba wypełnić lukę kompetencyjną. Konieczna może być zmiana zasad, na jakich współpracujecie.&lt;/p&gt;

&lt;h2 id=&quot;podsumowanie&quot;&gt;Podsumowanie&lt;/h2&gt;

&lt;p&gt;Siłą zwinnego zespołu jest zdolność do wspólnego rozwiązywania problemów. Silniejsi podciągają słabszych, słabsi uczą się od silniejszych. Silniejsi poszerzają zakres kompetencji, słabsi ulepszają swoje obecne umiejętności. Pytania słabszych napędzają myślenie silniejszych. Im jesteście lepsi jako zespół, tym lepiej organizujecie pracę i tym bardziej jesteście zadowoleni z jej efektów.&lt;/p&gt;

</description>
        <pubDate>Mon, 09 Jul 2018 05:00:00 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2018/07/zwinny-zespol/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2018/07/zwinny-zespol/</guid>
        
        <category>teamwork</category>
        
        <category>agile</category>
        
        
      </item>
    
      <item>
        <title>Podstawy pracy zespołowej</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-teamwork.jpg&quot; alt=&quot;Teamwork&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Programista ma znać się na programowaniu. Ale czy to wystarczy do rozwijania stabilnych projektów? Czy programista bez umiejętności miękkich jest wartościowy?&lt;/p&gt;

&lt;p&gt;Nie.&lt;/p&gt;

&lt;p&gt;Po pierwsze, bardzo rzadko zdarza się, aby projekt był rozwijany przez jednego jajogłowego, który w piwnicy wyprodukuje cały kod. Jeżeli pracujesz nad czymś większym niż kalkulator z 4 operacjami, prawdopodobnie robisz to we współpracy z innymi programistami. Od ustalania wspólnego technicznego kierunku projektu, aż po codzienne prace na repozytorium, wszystko wymaga dyscypliny i jedności wszystkich członków zespołu. Jedna czarna owca może skutecznie zabić motywację kolegów i korkować pracę.&lt;/p&gt;

&lt;p&gt;Po drugie, projekty IT są tworzone dla biznesu. Za wszystkimi działaniami programistów stoją potrzeby i cele interesariuszy. Nawet w projektach kaskadowych (&lt;em&gt;waterfall&lt;/em&gt;), na którymś etapie natkniesz się na kogoś niemówiącego językiem technicznym. Nie ma znaczenia, czy to będzie klient, czy kierownik projektu. Jeżeli nie umiesz wyjaśnić działań technicznych używając języka nietechnicznego, redukujesz swoją wartość do małpy klepiącej w klawiaturę.&lt;/p&gt;

&lt;h2 id=&quot;czym-jest-zespół&quot;&gt;Czym jest zespół?&lt;/h2&gt;

&lt;p&gt;Zespół jest zbiorem ludzi mających za zadanie zrealizowanie potrzeb interesariuszy. Nie muszą to być wyłącznie programiści. Właściciel produktu, menedżer projektu, scrum master lub ktokolwiek inny powiązany z celem projektu może być jego częścią. Ludzie w zespole znają się wzajemnie - wiedzą o mocnych i słabych stronach kolegów. Każdy w zespole pomaga innym, aby przybliżyć zespół do wspólnego celu. Członkowie zespołu wzajemnie uzupełniają swoje kwalifikacje. Zespół może ulegać zmianom w trakcie trwania projektu. Zmieniają się jakość i sposoby komunikacji.&lt;/p&gt;

&lt;p&gt;Kilka rzeczy może wskazywać na to, że nie jesteś częścią zespołu:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;należysz do kilku “zespołów” jednocześnie,&lt;/li&gt;
  &lt;li&gt;każdy w “zespole” pracuje nad innym projektem,&lt;/li&gt;
  &lt;li&gt;“zespół” nie ma wspólnego celu,&lt;/li&gt;
  &lt;li&gt;członkowie “zespołu” mają sztywno przydzielone zadania lub fragmenty projektu i nie wchodzą w silosy kompetencyjne innych.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;na-twardo-czy-na-miękko&quot;&gt;Na twardo czy na miękko?&lt;/h2&gt;

&lt;p&gt;Zespoły są mniej lub bardziej zgrane. Mają mniej lub więcej wpływu na kształt projektu. Zwykle jest to związane z wybraną metodyką. Metodyki twarde (np. Waterfall, XPrince) faworyzują formalizację i sztywny podział prac. Najważniejsze jest zrobienie własnego kawałka. Resztą zajmą się inni. Z kolei metodyki miękkie (np. Scrum, Kanban) stawiają na współpracę grupy ludzi w celu wypracowania jak największej wartości.&lt;/p&gt;

&lt;p&gt;Metodyki twarde są z pozoru prostsze we wdrożeniu. Sztywne powiązania między ludźmi, dedykowane osoby do tłumaczenia potrzeb biznesu na  zadania programistyczne, niezmienny zakres i wizja projektu. Niestety, projekty mają się nijak do założeń metodyk twardych: zakres i wizja projektów nie są stałe. Czasem wynika to ze zmieniających się potrzeb rynku, czasem ze zbyt powierzchownej analizy przed podpisaniem kontraktu.&lt;/p&gt;

&lt;p&gt;Metodyki miękkie stawiają na gotowość na zmianę, dzięki czemu są dostosowane do świata rzeczywistego. Wizja projektu jest płynna. Dużo łatwiej sprawdzić pomysł, zanim wejdziemy w niego z pełnym budżetem. Ciągła zmiana jest wyzwaniem i wymaga dużo częstszej i dokładniejszej komunikacji.&lt;/p&gt;

&lt;h2 id=&quot;oliwienie-trybików&quot;&gt;Oliwienie trybików&lt;/h2&gt;

&lt;p&gt;To nie jest tak, że powiecie sobie raz: mamy proces, teraz każdy może się zająć swoją robotą. Proces, podobnie jak kod, rozpada się z upływem czasu. Musicie go nieustannie naprawiać i dostosowywać do obecnych warunków.&lt;/p&gt;

&lt;p&gt;Do poprawiania procesu przydatna jest retrospektywa. Jest to spotkanie, na którym omawiacie ostatnie problemy, ale także sukcesy. Dobra retrospektywa pozwala na podnoszenie jakości spotkań, dlatego powinniście ją wykonywać przy zachowaniu wzajemnego szacunku i przestrzegając dodatkowych zasad, np. ustrukturyzowanie spotkania, głosowanie na tematy, wyznaczanie ram czasowych na pojedynczy temat.&lt;/p&gt;

&lt;p&gt;Jakość procesu zależy od tego, jak dobrze się rozumiecie. Im lepiej się znacie, tym lepiej się dogadujecie i wspieracie w realizacji projektu. Dlatego warto się czasem wyrwać po pracy i zrobić coś razem. Poza konwencjonalnym piwem w barze, masz szeroki wachlarz możliwości. Najlepiej sprawdzają się gry wymagające zgrania. Możecie pograć w planszówki lub postrzelać do siebie na paintballu albo laser tagu. Nakłoń innych do spróbowania czegoś nowego.&lt;/p&gt;

&lt;h2 id=&quot;podsumowanie&quot;&gt;Podsumowanie&lt;/h2&gt;

&lt;p&gt;Nie ma znaczenia, czy robisz software na twardo, czy na miękko. Tylko rozmowa z ludźmi poprawi Twoje zrozumienie tego co i dlaczego robisz. Wraz z zespołem zdołacie wykonać rzeczy, na które w pojedynkę nie macie szans.&lt;/p&gt;

&lt;p&gt;Czy czujesz się częścią zespołu?&lt;/p&gt;
</description>
        <pubDate>Sat, 26 May 2018 09:00:00 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2018/05/podstawy-pracy-zespolowej/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2018/05/podstawy-pracy-zespolowej/</guid>
        
        <category>teamwork</category>
        
        <category>agile</category>
        
        
      </item>
    
      <item>
        <title>Narzędzia programisty: Gulp</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-devtools-gulpjs.png&quot; alt=&quot;Gulp.js post main image&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Ostatnio pisałem o automatyzacji. Jest to proces wymagający dobrania odpowiedniego narzędzia. Dzisiaj skupię się na jednym z nich - Gulp.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Gulp&lt;/em&gt; jest jednym z narzędzi służącym do automatyzacji.&lt;/strong&gt; Strona projektu opisuje go jako &lt;em&gt;streaming build system&lt;/em&gt;. W niektórych miejscach widnieje jako &lt;em&gt;task runner&lt;/em&gt;. Zwał jak zwał. Wiele nazw na to samo. Gulp jest zwykle używany do automatyzowania webdevelopmentu. Prawdę mówiąc sam używam go do tego celu, jednak można go wykorzystać w dowolny inny sposób. &lt;strong&gt;Musisz mieć jedynie zbiór plików, na których chcesz operować oraz opis tego, co chcesz zrobić.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O tym dlaczego warto automatyzować pisałem w &lt;a href=&quot;/2016/10/automatyzacja-wprowadzenie/&quot;&gt;poprzednim poście&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;jak-to-działa&quot;&gt;Jak to działa?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Gulp jest narzędziem uruchamianym w środowisku &lt;em&gt;node.js&lt;/em&gt;.&lt;/strong&gt; Co prawda sens robienia aplikacji webowych w &lt;em&gt;node&lt;/em&gt; jest mocno dyskusyjny, ale narzędzia na tej platformie są przemyślane. &lt;strong&gt;Gulp operuje na strumieniach.&lt;/strong&gt; Oznacza to, że wszystkie stany pośrednie są przechowywane w pamięci, zamiast zapisywania np. tymczasowych plików na dysku. Gulp jest narzędziem konsolowym, jednak w świecie .NET zadania gulpa można go bez problemu uruchomić z poziomu &lt;em&gt;Visual Studio&lt;/em&gt; (od wersji 2015). Gulpa można użyć do wielu zastosowań. Najpopularniejszymi z nich są:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;weryfikacja poprawności składni (lintery),&lt;/li&gt;
  &lt;li&gt;transpilacja LESS/SASS -&amp;gt; CSS,&lt;/li&gt;
  &lt;li&gt;transpilacja TypeScript/ECMAScript* -&amp;gt; JavaScript,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/05/bundler-w-asp-net/&quot;&gt;minifikacja&lt;/a&gt; plików CSS/JavaScript/HTML,&lt;/li&gt;
  &lt;li&gt;zmiana rozmiarów obrazków i optymalizacja kompresji,&lt;/li&gt;
  &lt;li&gt;kopiowanie plików lub budowanie paczki przed deployem,&lt;/li&gt;
  &lt;li&gt;deployowanie,&lt;/li&gt;
  &lt;li&gt;czyszczenie zbudowanych plików.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;konfiguracja&quot;&gt;Konfiguracja&lt;/h2&gt;

&lt;p&gt;Pracę z Gulpem rozpoczynamy od instalacji Node.js, npm i samego Gulpa. Node.js i npma najszybciej zainstalujemy za pomocą &lt;a href=&quot;https://chocolatey.org/&quot;&gt;&lt;em&gt;Chocolatey&lt;/em&gt; (Windows)&lt;/a&gt;, &lt;a href=&quot;http://brew.sh/index_pl.html&quot;&gt;&lt;em&gt;Homebrew&lt;/em&gt; (macOS)&lt;/a&gt;, apt-get (Linux) lub dowolnego innego managera pakietów.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Windows&lt;/span&gt;
choco &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;nodejs.install

&lt;span class=&quot;c&quot;&gt;# macOS&lt;/span&gt;
brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;node

&lt;span class=&quot;c&quot;&gt;# Linux&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# poradzicie sobie :-)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Następnie przechodzimy do instalacji samego Gulpa. &lt;strong&gt;Gulp musi być zainstalowany globalnie w systemie oraz w samym projekcie.&lt;/strong&gt; Przechodzimy do katalogu projektu, który będziemy automatyzować i wykonujemy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;npm init
&lt;span class=&quot;c&quot;&gt;# wykonujemy wszystkie kroki&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# poszczególne wartości nie będą miały na nic wpływu&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# możemy dusić [ENTER] aż do wyjścia z polecenia&lt;/span&gt;

npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; gulp
npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt; gulp&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Możemy teraz odpalić gulpa&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gulp
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;08:35:10] No gulpfile found&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Oczywiście polecenie się posypało. Nie mamy jeszcze opisu żadnego zadania, które chcemy wykonywać. Opis ten umieszczamy w pliku &lt;em&gt;gulpfile.js&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;gulpfilejs&quot;&gt;gulpfile.js&lt;/h3&gt;

&lt;p&gt;Czas na zrobienie pierwszego zadania! Załóżmy, że chcemy zbudować pliki LESS z katalogu &lt;em&gt;/src/less/&lt;/em&gt;, zminifikować je i umieścić w &lt;em&gt;dist/css/&lt;/em&gt;. Chcemy, aby właściwości CSS były prefixowane w celu zapewnienia wsparcia w przeglądarkach 2 wersje wstecz. Będziemy potrzebowali do tego kilku pluginów. Z konsoli/terminala wykonujemy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt; gulp-autoprefixer gulp-clean-css gulp-cleancss gulp-concat gulp-less gulp-lesshint gulp-load-plugins through&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Mamy wszystko, czego potrzebujemy. Teraz wystarczy dodać plik &lt;em&gt;gulpfile.js&lt;/em&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;autoprefixer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-autoprefixer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;less&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-concat&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;cleanCss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-cleancss&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/less/*.less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;less&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;autoprefixer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;browsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;last 2 version&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;main.min.css&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cleanCss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;dist/css&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Teraz wystarczy uruchomić zadanie. Zadanie &lt;em&gt;default&lt;/em&gt; jest domyślnym zadaniem gulpa, więc nie musimy podawać jego nazwy. Jeżeli jednak chcemy to zrobić, wpisujemy w konsoli/terminalu:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gulp default
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;09:20:55] Using gulpfile ~/Workspace/gulptest/gulpfile.js
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;09:20:55] Starting &lt;span class=&quot;s1&quot;&gt;'default'&lt;/span&gt;...
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;09:20:55] Finished &lt;span class=&quot;s1&quot;&gt;'default'&lt;/span&gt; after 19 ms&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;W ten sposób wygenerował nam się plik &lt;em&gt;main.min.css&lt;/em&gt; w katalogu &lt;em&gt;dist/css/&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Był to bardzo prosty przykład. Przyjrzyjmy się czemuś odrobinę bardziej skomplikowanemu.&lt;/p&gt;

&lt;h3 id=&quot;zależność-zadań&quot;&gt;Zależność zadań&lt;/h3&gt;

&lt;p&gt;Chcemy zbudować aplikację składającą się z plików LESS, TypeScript i HTML. Chcemy wykonać poszczególne zadania:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;lintowanie (weryfikacja składni) plików LESS,&lt;/li&gt;
  &lt;li&gt;lintowanie (weryfikacja składni) plików TS,&lt;/li&gt;
  &lt;li&gt;budowanie plików LESS,&lt;/li&gt;
  &lt;li&gt;budowanie plików TS,&lt;/li&gt;
  &lt;li&gt;minifikacja zbudowanych plików CSS,&lt;/li&gt;
  &lt;li&gt;minifikacja zbudowanych plików JS,&lt;/li&gt;
  &lt;li&gt;minifikacja plików HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Niektóre zadania są od siebie zależne.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Budowanie plików LESS nie ma sensu, dopóki nie przejdzie ich weryfikacja.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Należy przeanalizować, które z zadań mogą być zastosowane bez uruchamiania innych zadań. Zadania nie mogą przekazywać strumienia pomiędzy sobą. W celu przekazania danych pomiędzy zadaniami konieczne jest zapisanie plików na dysku, a następnie ich ponowne załadowanie.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Weryfikacja składni plików LESS ma sens jako osobne zadanie. Minifikacja plików LESS jest zawsze powiązana z ich budowaniem (możemy generować pliki .css i .min.css).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Żeby zauważyć zależności, najłatwiej będzie narysować skierowany pseudograf zadań:&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-devtools-gulpjs-dependencies-graph.jpg&quot; alt=&quot;Pseudograf zależności&quot; width=&quot;980&quot; height=&quot;735&quot; /&gt;
&lt;figcaption&gt;Pseudograf zależności&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Zadania, które muszą zostać wykonane przed rozpoczęciem bieżącego zadania podajemy jako drugi parametr funkcji &lt;em&gt;gulp.task()&lt;/em&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build:less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build:ts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Finished build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;obserwowanie-zmian-w-plikach&quot;&gt;Obserwowanie zmian w plikach&lt;/h3&gt;

&lt;p&gt;Pracując nad aplikacją zwykle potrzebujemy ją przebudować po zmianie w plikach źródłowych. Gulp oferuje możliwość śledzenia zmian na plikach, w związku z czym możemy wywołać callback. Warto jest także dodać zadanie budowania aplikacji jako zależność &lt;em&gt;watcha&lt;/em&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/less/*.less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build:less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/ts/*.ts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build:ts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;ekstrakcja-ścieżek-i-danych-dostępowych&quot;&gt;Ekstrakcja ścieżek i danych dostępowych&lt;/h3&gt;

&lt;p&gt;W pliku &lt;em&gt;gulpfile.js&lt;/em&gt; znajduje się wiele różnych ścieżek. Część z nich służy do przeszukiwania plików źródłowych. Część jest ścieżką dla plików wynikowych. Do tego dochodzą różnego rodzaju dane dostępowe, np. hasła do ftp, klucze do chmury. Żeby zapanować nad tym chaosem, możemy wydzielić ścieżki i dane dostępowe do odrębnych plików. Osobiście ścieżki wyciągam do &lt;em&gt;gulp.config.js&lt;/em&gt;, a dane dostępowe do &lt;em&gt;secrets.json&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;gulp.config.js&lt;/em&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;use strict&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buildPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./dist/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;buildPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buildPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;buildCssPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;buildPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;css/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

        &lt;span class=&quot;na&quot;&gt;lessBuildFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./src/*.less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;

        &lt;span class=&quot;na&quot;&gt;lessWatchFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./src/**/*.less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;secrets.json&lt;/em&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;azureBlobStorage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;account&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(...)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(...)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(...)&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;azureFtp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;host&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(...)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(...)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(...)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;remotePath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(...)&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Po utworzeniu tych plików jesteśmy w stanie uzyskać do nich dostęp w &lt;em&gt;gulpfile.js&lt;/em&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./gulp.config.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;secrets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./secrets.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// (...)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lessBuildFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;less&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;autoprefixer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;browsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;last 2 version&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;main.min.css&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cleanCss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buildCssPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Na deser zostało jeszcze zmniejszenie liczby upierdliwych &lt;em&gt;require&lt;/em&gt;. Za pomocą &lt;em&gt;gulp-load-plugins&lt;/em&gt; usuwamy wszystkie załączenia pluginów z nazwą &lt;em&gt;gulp-*&lt;/em&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/* PRZED */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;autoprefixer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-autoprefixer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;less&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-concat&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;cleanCss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-cleancss&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// (...)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cleanCss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/* PO */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-load-plugins&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)();&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// (...)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cleanCss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;podsumowanie&quot;&gt;Podsumowanie&lt;/h2&gt;

&lt;p&gt;W wyniku wszystkich wymienionych operacji dostaliśmy następujący gulpfile:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./gulp.config.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;secrets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./secrets.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gulp-load-plugins&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)();&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build:less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lessBuildFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build:less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;build:less&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lessBuildFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;less&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;autoprefixer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;browsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;last 2 version&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;main.css&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cleanCss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;main.min.css&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buildCssPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Nie jest to kod pasujący do każdej sytuacji, ale może stanowić podstawę do Twojego pierwszego skryptu automatyzującego.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cały projekt umieściłem na &lt;a href=&quot;https://github.com/Keraxel/Demos/tree/master/gulptest&quot;&gt;Githubie&lt;/a&gt;. Możesz się nim pobawić, żeby poczuć w jaki sposób działa Gulp.&lt;/em&gt;&lt;/p&gt;

</description>
        <pubDate>Mon, 28 Nov 2016 01:25:00 -0600</pubDate>
        <link>https://www.binarythoughts.pl/2016/11/narzedzia-programisty-gulp/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2016/11/narzedzia-programisty-gulp/</guid>
        
        <category>webdev</category>
        
        <category>toolsSeries</category>
        
        <category>automation</category>
        
        <category>gulp</category>
        
        
      </item>
    
      <item>
        <title>Automatyzacja: wprowadzenie</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-automation-introduction.png&quot; alt=&quot;Golf cart at airport&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Cześć!&lt;/p&gt;

&lt;p&gt;Dzisiejsze IT staje przed wyzwaniem automatyzacji powtarzalnych procesów. Nigdy nie zdarzyło Ci się budować projektu, kopiować paczki na serwer, a następnie ręcznie przeklikać, czy wszystko działa prawidłowo? Nigdy nie wkleiłeś produkcyjnych kluczy do kodu przed wrzuceniem aplikacji do sklepu? W takim razie ten wpis nie jest dla Ciebie, jednorożocu Ty! W przeciwnym wypadku, zapraszam.&lt;/p&gt;

&lt;h2 id=&quot;upierdliwe-życie-programisty&quot;&gt;Upierdliwe życie programisty&lt;/h2&gt;

&lt;p&gt;Pracowałem kiedyś nad dużym oprogramowaniem. Monolitem, takim pisanym przez 100 - 500 osób. Wiesz, kilkanaście środowisk, z czego 2 używane etc. Jak w każdym projekcie w 2010’s, mieliśmy serwer, który budował projekt. Jakaś mądra głowa pochyliła się nad tematem i stwierdziła, że musi być. W końcu automatyzacja to szybszy feedback i mniejsze koszty, bierzemy! Był tylko jeden problem - zbudowanie całego projektu trwało kilka godzin.&lt;/p&gt;

&lt;p&gt;Dodatkowo, samo zbudowanie wszystkiego nie oznaczało, że oprogramowanie nadaje się do wdrożenia. W końcu moduł mógł się zbudować, ale nie być podpięty pod resztę projektu (sic!). Zamiast skupić się na rozwijaniu oprogramowania, każdy programista musiał kontrolować, czy konfiguracja jest poprawna. Drobne rzeczy są łatwe do przeoczenia. Z tego powodu soft często się wykładał z niejasnych przyczyn.&lt;/p&gt;

&lt;h2 id=&quot;mniejsza-skala-te-same-problemy&quot;&gt;Mniejsza skala, te same problemy&lt;/h2&gt;

&lt;p&gt;Zejdźmy jednak w tej chwili na ziemię. Nie każdy projekt jest tak opasły. Co nie znaczy, że problemy są inne. Prześledźmy taki przypadek. Tworzysz projekt w kilka osób. Wdrożenia projektu może dokonać tylko przedstawiciel klienta. Polityka bezpieczeństwa albo inny korporacyjny szit, zdarza się. W związku z tym, wszystkie hasła muszą zostać podmienione przez osobę wykonującą deploy. Przy okazji, człowiek ten ulega pokusie “poprawienia” kilku rzeczy w konfiguracji, według swojego &lt;em&gt;widzimisię&lt;/em&gt;. W ten sposób otrzymujesz niespójny i zmodyfikowany produkt, za który odpowiadasz.&lt;/p&gt;

&lt;h2 id=&quot;lokalne-podwórko&quot;&gt;Lokalne podwórko&lt;/h2&gt;

&lt;p&gt;Mam bloga na statycznym CMSie. Każda zmiana na stronie wiąże się ze zbudowaniem HTMLi, styli etc. Pliki wypycham w dwa miejsca: FTP z Azure Web App oraz Azure Blob Storage. Za każdym razem muszę mieć osobną paczkę do wrzucenia w każde z miejsc. Dodatkowo mam dwa różne pliki Web.config - jeden dla serwera testowego i drugi dla produkcji (produkcja ma HTTPS z HSTS). Ręczne dobranie plików, które dostaję z Jekylla, zbudowanie LESSów, podzielenie na FTP i Bloba i wrzucenie na serwer zajmuje jakieś 10 minut i nie mam pewności, że wszystko jest na miejscu.&lt;/p&gt;

&lt;h2 id=&quot;dlaczego-automatyzować&quot;&gt;Dlaczego automatyzować?&lt;/h2&gt;

&lt;p&gt;Wymienione sytuacje różnią się poziomem złożoności. Można jednak wyodrębnić z nich kilka powodów, dla których należy przeprowadzić automatyzację procesu:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rozwój oprogramowania wymaga coraz większej liczby ręcznie konfigurowanych elementów,&lt;/li&gt;
  &lt;li&gt;każdy nowy element jest kolejnym, możliwym do popełnienia, błędem… błędem który, prędzej czy później, wreszcie popełnisz,&lt;/li&gt;
  &lt;li&gt;ludzie są słabi w powtarzaniu czynności, w przeciwieństwie do komputerów,&lt;/li&gt;
  &lt;li&gt;skrypt automatyzujący jest dla projektu tym, czym &lt;em&gt;testy uczące&lt;/em&gt; dla kodu,&lt;/li&gt;
  &lt;li&gt;automatyzacja może zastapić dokumentację konfigurowania projektu, która jest zwykle nieaktualna lub nikt jej nie czyta.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;czym-automatyzować&quot;&gt;Czym automatyzować?&lt;/h2&gt;

&lt;p&gt;Możliwości automatyzacji są bardzo szerokie. Popularne są dedykowane narzędzia automatyzujące, budujące oraz task runnery. Tego typu narzędzia mogą polegać na uruchamianiu kolejnych komend z powłoki (jak ma to miejsce w &lt;em&gt;Make&lt;/em&gt;), lub stosować dedykowane API (&lt;em&gt;Grunt.js&lt;/em&gt;, &lt;em&gt;Gulp.js&lt;/em&gt;, &lt;em&gt;MSBuild&lt;/em&gt;). Mogą operować na kolejnych artefaktach w systemie plików lub przetwarzać wszystko w pamięci za pomocą strumieni.&lt;/p&gt;

&lt;p&gt;Innymi możliwościami są:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;skrypty powłoki systemowej, (&lt;em&gt;bash&lt;/em&gt;, &lt;em&gt;pliki bat&lt;/em&gt;),&lt;/li&gt;
  &lt;li&gt;skrypty lub programy napisane w dowolnych językach programowania (&lt;em&gt;C#&lt;/em&gt;, &lt;em&gt;Python&lt;/em&gt;, &lt;em&gt;Ruby&lt;/em&gt;),&lt;/li&gt;
  &lt;li&gt;oprogramowanie uruchamiające skrypty cyklicznie (&lt;em&gt;cron&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Metoda jest w rzeczywistości dowolna. Liczy się łatwość osiągnięcia celu, łatwość uruchomienia skryptu/programu oraz łatwość utrzymywania przez zespół. Zupełnie jak z każdym innym programem.&lt;/p&gt;

&lt;h2 id=&quot;kiedy-i-jak-automatyzować&quot;&gt;Kiedy i jak automatyzować?&lt;/h2&gt;

&lt;p&gt;O automatyzacji należy zacząć myśleć w momencie, gdy jakaś powtarzalna czynność staje się uciążliwa lub wymaga przypominania sobie całego procesu. Takie sytuacje są powszechne. Pamiętaj jednak, że program automatyzujący jest tak samo podatny na błędy, jak każdy inny software. Zbędna automatyzacja może skończyć się w następujący sposób:&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-automation-intruduction-xkcd-automation.png&quot; alt=&quot;xkcd: Automation&quot; width=&quot;404&quot; height=&quot;408&quot; /&gt;
&lt;figcaption&gt;xkcd: Automation&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Jeśli jednak automatyzacja się opłaci, należy przetestować skrypt przed wykorzystaniem go w systemie produkcyjnym. Jak to zrobić? Przede wszystkim, należy odseparować konfigurację (ścieżki do katalogów, hasła, klucze) od właściwego kodu. Następnie trzeba zmodyfikować konfigurację w taki sposób, aby nie łączyła się w żaden sposób z produkcją lub nie narobiła bałaganu w przypadku jakiegoś babola.&lt;/p&gt;
</description>
        <pubDate>Thu, 20 Oct 2016 07:10:00 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2016/10/automatyzacja-wprowadzenie/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2016/10/automatyzacja-wprowadzenie/</guid>
        
        <category>automation</category>
        
        
      </item>
    
      <item>
        <title>CSS - zapanuj nad stajnią Augiasza</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-css.jpg&quot; alt=&quot;Stable&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Siemano! Obejrzałem najnowszy odcinek GoT, więc czas na kreatywną pracę z tekstem!&lt;/p&gt;

&lt;p&gt;Ostatnio w pracy dużo siedzę przy front-endzie. Co prawda I don’t speak JavaScript, ale front-end to nie tylko skrypty. Osobiście dużo więcej frajdy sprawia mi pisanie deklaratywnie w HTMLu i CSSach. Bardzo długo do tematu &lt;em&gt;programowania w HTMLu&lt;/em&gt; podchodziłem drwiąco. Musicie jednak wiedzieć, że opisanie wyglądu i zachowania strony to nie lada wyczyn. Podział strony na sensowne częsci w HTMLu jest względnie prosty (w końcu wstawiamy tam dane, helloooo). Dużym problemem są za to style, które nakładają się na siebie w często mało oczywisty sposób. W dzisiejszym wpisie przybliżę więc temat podziału CSSów na moduły.&lt;/p&gt;

&lt;h2 id=&quot;css-czyli-jak-bardzo-przegrałeś&quot;&gt;CSS, czyli jak bardzo przegrałeś&lt;/h2&gt;

&lt;p&gt;W ramach przypomnienia jak w ogóle wygląda CSS, zapisałem przykładową regułę:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nt&quot;&gt;selector&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;another-property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Selektory odpowiadają za wybór elementów, na które zostaną nałożone style. Możliwy jest wybór elementów strony przy pomocy tagów HTML, id lub klas. Możliwe jest również łączenie selektorów w celu uszczegółowienia tego, co ma zostać ostylowane, np. można ostylować wszystkie elementy &lt;em&gt;p&lt;/em&gt;, będące potomkami elementu &lt;em&gt;article&lt;/em&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nt&quot;&gt;article&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;pink&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Właściwości (ang. &lt;em&gt;property&lt;/em&gt;) i wartości (ang. &lt;em&gt;value&lt;/em&gt;) odpowiadają za zmianę wyglądu lub zachowania wybranych elementów. W powyższym przykładzie, wszystkie elementy &lt;em&gt;p&lt;/em&gt;, będące potomkami &lt;em&gt;article&lt;/em&gt; będą miały różowe tło.&lt;/p&gt;

&lt;p&gt;Albo nie wszystkie… Pisiont na pisiont. CSS jest wyposażony w mechanizm rozwiązywania konfliktów wg. specyficzności (ang. &lt;em&gt;specificity&lt;/em&gt;). Wygrywa selektor najsilniejszy, a więc taki, którego specyficzność jest najwyższa. Specyficzność zależy od rodzaju selektora, jego złożoności i prawdopodobnie od promieniowania kosmicznego oraz liczby Yeti w promieniu 6 mil. Chociaż co do dwóch pierwszych nie jestem pewien. Reguła kciuka jest następująca: im bardziej zakręcony selektor, tym wyższa specyficzność. Prosty przykład wrzuciłem na &lt;a href=&quot;https://jsfiddle.net/86cnh5kg/&quot;&gt;JSFiddle&lt;/a&gt;:&lt;/p&gt;

&lt;iframe width=&quot;100%&quot; height=&quot;300&quot; src=&quot;//jsfiddle.net/86cnh5kg/embedded/html,css,result/&quot; allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Problem z CSSem zaczyna się w momencie, w którym struktura strony staje się skomplikowana i należy zdecydować, od którego elementu drzewa będziemy zaczynali selektor.&lt;/p&gt;

&lt;h2 id=&quot;jak-wyznaczyć-korzeń-selektora&quot;&gt;Jak wyznaczyć korzeń selektora?&lt;/h2&gt;

&lt;p&gt;Problem da się zauważyć już w podlinkowanym wcześniej przykładzie. Zacząłem selektor od elementu &lt;em&gt;article&lt;/em&gt;. Czy na pewno był on wymagany? Albo był, albo nie był. Wszystko zależy tak naprawdę od kontekstu. Podejmując decyzję o korzeniu hierarchii selektora, zadaję sobie następujące pytania:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Czy elementy &lt;em&gt;p&lt;/em&gt; wystąpią w przyszłości poza artykułem?&lt;/li&gt;
  &lt;li&gt;Czy elementy &lt;em&gt;p&lt;/em&gt; poza artykułem powinny mieć nałożone te same style?&lt;/li&gt;
  &lt;li&gt;Czy wszystkie elementy &lt;em&gt;p&lt;/em&gt; w artykule powinny mieć nadany określony styl? (Może warto uszczegółowić selektor?)&lt;/li&gt;
  &lt;li&gt;Czy &lt;em&gt;article&lt;/em&gt; jest odrębnym komponentem?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ogólna zasada jest następująca: wybierz najmniej szczegółowy selektor, który spełni wszystkie wymagania. Stosując zbyt skomplikowane selektory prosisz się o problemy ze specyficznością w przypadku nadpisywania stylu.&lt;/p&gt;

&lt;h2 id=&quot;less-czyli-zagnieżdżenia-zmienne-i-funkcje-w-stylach&quot;&gt;LESS, czyli zagnieżdżenia, zmienne i funkcje w stylach&lt;/h2&gt;

&lt;p&gt;Skoro już jesteśmy przy skomplikowanych selektorach, chciałbym pokazać Ci jedno z narzędzi ułatwiających pracę z bardzo złożonymi arkuszami stylów. Jest nim LESS. LESS jest nadzbiorem języka CSS. Oznacza to tyle, że każdy CSS jest poprawnym kodem LESS, dzięki czemu możesz stopniowo przepisywać style na LESS.&lt;/p&gt;

&lt;h3 id=&quot;zagnieżdżenia&quot;&gt;Zagnieżdżenia&lt;/h3&gt;

&lt;p&gt;LESS pozwala na zagnieżdżanie selektorów. Oznacza to, że przykładowy CSS można przepisać na poniższą postać:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-less&quot; data-lang=&quot;less&quot;&gt;article {
    p {
        color: pink;

        &amp;amp;.black-as-hell {
            color: black;
        }
    }

    *:last-child {
        color: green;
     }
}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Każdy poziom zagnieżdżenia oznacza kolejną składową selektora. Jeżeli chcemy uzyskać składową selektora złożoną np. z taga i klasy, należy skorzystać z operatora &lt;em&gt;&amp;amp;&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;zmienne&quot;&gt;Zmienne&lt;/h3&gt;

&lt;p&gt;Bardzo często projekt strony przewiduje wykorzystywanie jednego koloru w wielu miejscach. To samo może dotyczyć np. marginesów oraz czcionek. W takiej sytuacji LESS oferuje nam zmienne.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-less&quot; data-lang=&quot;less&quot;&gt;@paragraph-color: pink;
@alternative-paragraph-color: black;
@last-element-color: green;

article {
    p {
        color: @paragraph-color;

        &amp;amp;.black-as-hell {
            color: @alternative-paragraph-color;
        }
    }

    *:last-child {
        color: @last-element-color;
     }
}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ważne jest, aby nazwy zmiennych powiązane były ze znaczeniem elementów, do których będą wykorzystywane. Nazwanie zmiennej @black nie da nam żadnego zysku – zmodyfikowanie jej zawartości zmusi nas do zmiany jej nazwy.&lt;/p&gt;

&lt;h3 id=&quot;mixiny-i-funkcje&quot;&gt;Mixiny i funkcje&lt;/h3&gt;

&lt;p&gt;Język LESS oferuje możliwość definiowania parametryzowanych reguł. Taka reguła nosi nazwę &lt;em&gt;mixin&lt;/em&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-less&quot; data-lang=&quot;less&quot;&gt;.apply-color(@color) {
    color: @color;
}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Mixiny mają raczej ograniczone zastosowania, jednak są sytuacje, w których znacznie ułatwiają życie. Przykładem może być nadanie elementowi &lt;a href=&quot;https://css-tricks.com/snippets/css/clear-fix/&quot;&gt;clearfixa&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-less&quot; data-lang=&quot;less&quot;&gt;.clearfix() {
    zoom: 1;

    &amp;amp;:before,
    &amp;amp;:after {
        content: &quot;&quot;;
        display: table;
    }

    &amp;amp;:after {
        clear:  both;
    }
}

.floating-elements-container {
    .clearfix();
}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;LESS oferuje również zbiór wbudowanych funkcji, pozwalających na manipulowanie wartościami. Możliwe jest np. przyciemnienie koloru, nadanie przezroczystości lub wybranie mniejszej wartości (funkcja &lt;em&gt;min&lt;/em&gt;).&lt;/p&gt;

&lt;h3 id=&quot;podział-stylów-na-wiele-plików&quot;&gt;Podział stylów na wiele plików&lt;/h3&gt;

&lt;p&gt;Została nam najistotniejsza część naszej wędrówki przez krainę LESSa. Mając odpowiednio wydzielone moduły, wyodrębnione zmienne i mixiny, jesteśmy w stanie podzielić style na wiele plików. Osobiście stosuję następujące zasady:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;zmienne trafiają do variables.less,&lt;/li&gt;
  &lt;li&gt;mixiny trafiają do mixins.less,&lt;/li&gt;
  &lt;li&gt;każdy moduł trafia do osobnego pliku i załącza referencje do zmiennych i mixinów (za pomocą &lt;em&gt;@import (reference) “variables.less”&lt;/em&gt;),&lt;/li&gt;
  &lt;li&gt;jeżeli aplikacja posiada dużo stylów dla urządzeń mobilnych, trafiają one do osobnych plików, np. &lt;em&gt;nazwa-modulu.lg.less&lt;/em&gt;, &lt;em&gt;nazwa-modulu.md.less&lt;/em&gt; etc.&lt;/li&gt;
  &lt;li&gt;jeżeli style mobilne stanowią nie więcej niż 50 linii kodu, umieszczam je w plikach opisanych szerokością ekranu, np. &lt;em&gt;lg.less&lt;/em&gt;, &lt;em&gt;md.less&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;wady-i-alternatywy&quot;&gt;Wady i alternatywy&lt;/h3&gt;

&lt;p&gt;Język LESS zawiera jeden haczyk - przeglądarki go nie interpretują. W związku z tym, należy zbudować go do CSSa po stronie serwera. Obecnie nie stanowi to dużego problemu. Web Essentials dla Visual Studio posiada narzędzie do budowania LESSa. Takie możliwości posiadają również pluginy do &lt;em&gt;Gulpa&lt;/em&gt; i &lt;em&gt;Grunta&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Istnieje jedna realna alternatywa dla LESSa, a mianowicie język SASS. Oba języki posiadają porównywalne możliwości. Osobiście korzystam z LESSa, ponieważ był on dużo popularniejszy w świecie .NET gdy zaczynałem swoją przygodę z web developmentem. Siła nawyku :-)&lt;/p&gt;

&lt;p&gt;Używasz LESSa w swoich projektach? A może masz inny sposób radzenia sobie z chaosem w arkuszach stylów? Podziel się w komentarzach!&lt;/p&gt;

</description>
        <pubDate>Tue, 31 May 2016 16:30:00 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2016/05/css/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2016/05/css/</guid>
        
        <category>css</category>
        
        <category>less</category>
        
        
      </item>
    
      <item>
        <title>F#: wyrażenia</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-fsharp-expressions.jpg&quot; alt=&quot;Lion's expression&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Szalom!&lt;/p&gt;

&lt;p&gt;Witam się po hebrajsku, bo jedna z Wróżek-korektorek stwierdziła, że “hej” jest pedalskie. Ale do rzeczy. W kolejnym odcinku traktującym o języku F# chciałem się skupić na jednej z postawowych koncepcji programowania funkcyjnego, a mianowicie:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Funkcje są wyrażeniami&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;wyrażenia&quot;&gt;Wyrażenia&lt;/h2&gt;

&lt;p&gt;Czym jest owo wyrażenie? Mówiąc w skrócie, jest to funkcja, która nie zapisuje żadnych zmiennych pośrednich i zwraca wartość. Najprościej będzie mi to wyjaśnić na przykładzie.&lt;/p&gt;

&lt;p&gt;To nie jest wyrażenie:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ComputeHsvColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ComputeHue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;saturation&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ComputeSaturation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ComputeValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HsvColor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{0}{1}{2}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;saturation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To za to jest wyrażeniem:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ComputeHsvColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{0}{1}{2}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;ComputeHue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;ComputeSaturation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;ComputeValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Prawdziwy bałagan, prawda? Składnia nie powala, ale zajmiemy się nią później. W tej chwili ważne jest to, że uzyskaliśmy wyrażenie. Wyrażenie w C# najprościej rozpoznać po tym, że ciało funkcji zaczyna się od słowa kluczowego &lt;em&gt;return&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Co nam to właściwie dało? Brak utrzymywania stanu na zewnątrz fukcji powoduje, że są one od siebie odizolowane. W konsekwencji  funkcje można łatwo zamieniać między sobą i organizować w bardziej złożone fragmenty aplikacji. Jeżeli mieliście doświadczenie z testami jednostkowymi, to możecie dostrzec kolejny istotny benefit. Odizolowany kod jest bardzo prosty w przetestowaniu.&lt;/p&gt;

&lt;p&gt;Ok, ok. Testy to jedno, a czytelność kodu to drugie. Zajmijmy się więc tym zagadnieniem. F# oferuje kilka ciekawych rozwiązań, dzięki którym łatwiej zrozumiecie działanie wyrażeń.&lt;/p&gt;

&lt;h2 id=&quot;operacje-na-wyrażeniach-w-f&quot;&gt;Operacje na wyrażeniach w F#&lt;/h2&gt;

&lt;p&gt;F# posiada szeroki wachlarz lukrów składniowych, ułatwiających pracę z wyrażeniami. Z punktu widzenia dzisiejszego wpisu, szczególnie przydatne są trzy konstrukcje:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;dopasowywanie wzorców za pomocą match .. with,&lt;/li&gt;
  &lt;li&gt;operator forward pipe,&lt;/li&gt;
  &lt;li&gt;operator forward composition.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;dopasowywanie-wzorców&quot;&gt;Dopasowywanie wzorców&lt;/h3&gt;

&lt;p&gt;Dopasowywanie wzorców (ang. pattern matching) w F# realizuje się za pomocą operatora match .. with. Jest to taki switch na sterydach. W głowach doświadczonych programistów języków obiektowych powinna zapalić się czerwona lampka. Switch jest przecież brzydkim zapachem w kodzie, a jego wystąpienie oznacza zwykle brak lub źle zastosowane wzorce projektowe. W F# jest jednak inaczej.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot; data-lang=&quot;fsharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someFunction&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someArgument&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someDiffrentArgument&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someArgument&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;computeAnotherPartOfCode&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;someDiffrentArgument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doSomethingElse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;launchRocket&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Istotny jest fakt, że każde z dopasowań musi zwracać ten sam typ danych. Jeżeli funkcja zawiera jedynie dopasowywanie wzorców, można zastosować jeszcze krótszą składnię. Pierwszy parametr przekazany do funkcji jest wtedy obiektem dopasowywania:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot; data-lang=&quot;fsharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someFunction&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;someDiffrentArgument&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;computeAnotherPartOfCode&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;someDiffrentArgument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doSomethingElse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;launchRocket&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;W językach funkcyjnych powszechnie stosowane są listy ze wskaźnikami na następny element (ang. linked list) oraz krotki (ang. tuple). Dopasowania w F# pozwalają na czytelny zapis operacji na powyższych typach.&lt;/p&gt;

&lt;p&gt;Listę można podzielić na n pierwszych elementów oraz ogon:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot; data-lang=&quot;fsharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processListValues&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;head&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processListValues&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tail&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Możliwe jest również dopasowywanie do elementów w krotkach:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot; data-lang=&quot;fsharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processTuple&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ok, świetnie. Znamy kolejną konstrukcję w kolejnym &lt;a href=&quot;https://pl.wikipedia.org/wiki/Piet&quot;&gt;dziwnym&lt;/a&gt; &lt;a href=&quot;https://esolangs.org/wiki/Omgrofl&quot;&gt;języku&lt;/a&gt; &lt;a href=&quot;https://pl.wikipedia.org/wiki/Brainfuck&quot;&gt;programowania&lt;/a&gt;. Co w niej takiego niezwykłego? Otóż dopasowywanie wzorców:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;nie pozwala&lt;/strong&gt; na pominięcie jakiejkolwiek wartości z możliwego zbioru wejść,&lt;/li&gt;
  &lt;li&gt;wymusza zwrócenie obiektu,&lt;/li&gt;
  &lt;li&gt;pozwala na operowanie na jakimkolwiek obiekcie&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pominięcie wartości i modyfikowanie stanu zmiennych zamiast zwrócenia obiektu są powszechnymi problemami konstrukcji switch. To samo dotyczy dopasowań - F# nie jest ograniczony do stałych.&lt;/p&gt;

&lt;h3 id=&quot;forward-pipe&quot;&gt;Forward pipe&lt;/h3&gt;

&lt;p&gt;Ile razy zdarzyło wam się widzieć taki kod podobny do poniższego?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookedSmurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Cook&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConcoctMixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SmurfsLocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetSmurfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Smurfette&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CountSmurfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Kolejne zagnieżdżenia wywołań niesamowicie utrudniają analizę kodu. Możemy oczywiście podzelić powyższy kod na mniejsze zmienne:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;n&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Smurf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allSmurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SmurfsLocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetSmurfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Smurf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tastySmurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allSmurfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Smurfette&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;IMixture&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;baseMixture&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConcoctMixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tastySmurfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ICookedMixture&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookedMixture&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Cook&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;baseMixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookedSmurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookedMixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CountSmurfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;Spoiler: CountSmurfs ma następującą postać:&lt;/em&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CountSmurfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// all Smurfs escaped soooo... f/u Gargamel&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Wracając do tematu: F# pozwala na jeszcze prostsze połączenie wielu operacji. Wszystko to odbywa się dzięki operatorowi forward pipe. Operator ten przekazuje wynik operacji jako ostani argument do następnej fukcji:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot; data-lang=&quot;fsharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookedSmurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;getSmurfs&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;smurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smurfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Smurfette&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ToList&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concoctMixture&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cook&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;countSmurfs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Wygląda dużo prościej i czytelniej, prawda?&lt;/p&gt;

&lt;h3 id=&quot;forward-composition&quot;&gt;Forward composition&lt;/h3&gt;

&lt;p&gt;Operator forward pipe pozwala na przekazywanie argumentów do kolejnych fukcji. A co jeżeli chcielibyśmy zapisać fukcję jako zbiór kolejnych operacji, nie nazywając zmiennych wejściowych? Z pomocą przychodzi, oczywiście, operator forward composition:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-fsharp&quot; data-lang=&quot;fsharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;countCookedSmurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;smurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smurfs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Smurfette&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ToList&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concoctMixture&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cook&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;countSmurfs&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cookedSmurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;countCookedSmurfs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getSmurfs&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Operatory forward pipe i composition różnią się tak naprawdę jedynie początkowym przekazaniem parametru. W przypadku forward pipe parametr przychodzi ze środka funkcji, natomiast w composition - z zewnątrz.&lt;/p&gt;

&lt;h2 id=&quot;podsumowanie&quot;&gt;Podsumowanie&lt;/h2&gt;

&lt;p&gt;Wyrażenia same w sobie mogą powodować trudności w analizowaniu działania programu. Na szczęście składnia F# powoduje zwiększenie przejrzystości całego tego bałaganu.
Moim zdaniem wyrażenia plus dedykowana składnia dają w wyniku dużo przejrzystszy kod, niż chociażby w przypadku ce-płotka. A co Wy o tym myślicie?&lt;/p&gt;

&lt;h3 id=&quot;materiały-dodatkowe&quot;&gt;Materiały dodatkowe&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://fsharpforfunandprofit.com/posts/expressions-vs-statements/&quot;&gt;F# for fun and profit - Expressions vs. Statements&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Sat, 30 Apr 2016 12:00:00 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2016/04/fsharp-wyrazenia/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2016/04/fsharp-wyrazenia/</guid>
        
        <category>fsharp</category>
        
        <category>lang</category>
        
        
      </item>
    
      <item>
        <title>Dylematy programisty: var</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-var.jpg&quot; alt=&quot;Baseball Match&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Zawód programisty wiąże się z nieustannym wybieraniem pomiędzy złym, a gorszym. Nie inaczej jest ze słowem kluczowym var.&lt;/p&gt;

&lt;h2 id=&quot;czym-jest-var&quot;&gt;Czym jest var?&lt;/h2&gt;

&lt;p&gt;Słowo kluczowe var służy do inferencji typów na poziomie kompilacji C# do CIL. Inferencja polega na ustaleniu typu zmiennej na podstawie przypisywanej wartości. Var ma swoje korzenie w języku F#, gdzie inferencja jest jeszcze bardziej rozbudowana. Nie jest to w żadnym wypadku typ dynamiczny. Słowo kluczowe var można stosować jedynie wewnatrz metody - nie ma możliwości definiowania w ten sposób typów wejściowych i wyjściowych (w przeciwieństwie do F#), czy też typów pól w klasie.&lt;/p&gt;

&lt;p&gt;Ponieważ mój .NET trochę zardzewiał (a rdza słabo schodzi, bo nie piję coli ani nie smaruję się WD-40), byłem przekonany, że każdy developer C# używa go wszędzie gdzie się da. Okazało się, że istnieje spore grono wyznawców podawania typów wprost.&lt;/p&gt;

&lt;h2 id=&quot;dlaczego-warto-używać-var&quot;&gt;Dlaczego warto używać var?&lt;/h2&gt;

&lt;p&gt;Słowo kluczowe var, a co za tym idzie - ograniczona inferencja typów, nie zostały wprowadzone bez powodu. Do głównych zalet należą:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;zmiana przypisania wartości nie wymusza zmiany typu zmiennej,&lt;/li&gt;
  &lt;li&gt;zapis jest krótszy i czytelniejszy, szczególnie w przypadku rozbudowanych typów ogólnych (less is more),&lt;/li&gt;
  &lt;li&gt;wymusza przypisywanie wartości do zmiennej w miejscu jej deklaracji,&lt;/li&gt;
  &lt;li&gt;uwalnia od polegania na implementacji na rzecz interfejsu (np. w kolekcjach).&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sheepsCount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ExtendedComplicatedImportantRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelOne&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModelTwo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Elements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Important&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Dodatkowo var jest jedyną możliwością w przypadku tworzenia instancji typów anonimowych.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Amount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;108&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;w-jakich-sytuacjach-var-jest-utrudnieniem&quot;&gt;W jakich sytuacjach var jest utrudnieniem?&lt;/h2&gt;

&lt;p&gt;Stosowanie słowa var w każdej sytuacji wiąże się jednak z pewnymi komplikacjami:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;na code review nie widać typu zmiennej, przez co trudniej określić intencje autora kodu,&lt;/li&gt;
  &lt;li&gt;korzystanie że źle zaprojektowanego api jest mało czytelne,&lt;/li&gt;
  &lt;li&gt;odczytanie typu poza środowiskiem programistycznym z intellisense jest utrudnione.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contentUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ContentReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Spotkałem się również z metodą mieszaną - stosowanie var tylko w przypadku tworzenia nowego obiektu za pomocą konstuktora lub metody wytwórczej.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;secondElement&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;podsumowanie&quot;&gt;Podsumowanie&lt;/h2&gt;

&lt;p&gt;Osobiście stosuję var gdzie się da. Prawdę mówiąc mam wrażenie, że unikanie var jest wymówką dla złego nazywania zmiennych i pól. W końcu nazwa zmiennej powie wszystko o jej zawartości. A co jeżeli…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;n&quot;&gt;IRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Banana&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applesRepository&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Banana&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// a lot of crappy code&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(...)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// we don't know type of result just because of wrong variable name&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;applesRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;First&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Moje podejście dotyczy to jednak tylko moich własnych projektów. Pracując w zespole dużo istotniejsza jest spójność. W moim obecnym projekcie w pracy stosujemy metodę mieszaną.&lt;/p&gt;

&lt;p&gt;A wy? Używacie tego słowa kluczowego w swoich projektach?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PS. Jestem na etapie życia, w którym wszystko zaczyna zasuwać jak gepard goniący gazelę. Pisanie kolejnych postów często spada na dalszy plan. Dlatego potrzebowałem motywacji. Postanowiłem rzucić wyzwanie mojemu &lt;a href=&quot;http://akubiak.pl&quot;&gt;dobremu kumplowi Arkowi&lt;/a&gt;, który właśnie transferuje się z upadającego WP na Androida. Wyzwanie polega na opublikowaniu przynajmniej jednego wpisu w miesiącu. Arek, jak przystało na człowieka o wyglądzie drwala, podniósł rękawicę. Dzięki temu na naszych blogach będzie więcej contentu dla Was&lt;/em&gt; :-)&lt;/p&gt;

</description>
        <pubDate>Wed, 30 Mar 2016 14:10:00 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2016/03/dylematy-var/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2016/03/dylematy-var/</guid>
        
        <category>csharp</category>
        
        <category>lang</category>
        
        <category>dillema</category>
        
        
      </item>
    
      <item>
        <title>F#: po radosnej stronie programowania</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-fsharp-bright-side.jpg&quot; alt=&quot;Sunflowers&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Dwa lata temu spotkałem go poraz pierwszy. Cechowały go dziwna składnia, nienaturalny przepływ sterowania i komplikowanie najprostszych operacji do &lt;em&gt;rocket science&lt;/em&gt; na linked listach i rekurencji. Pomyślałem wtedy - jak można pisać w czymś takim?!
Byłem w błędzie.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;/ wow, temat wpisu w ogóle nie sugerował takiego plot twistu /&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;programowanie-funkcyjne&quot;&gt;Programowanie funkcyjne&lt;/h2&gt;

&lt;p&gt;Być może potknąłeś się o programowanie funkcyjne. Mógł to być wielki kamień stojący 20 metrów od Twojej ścieżki kariery. Tak, ten z wysprayowanym napisem “NIE DOTYKAĆ”. Jeżeli to Twój pierwszy kontakt z programowaniem funkcyjnym, to musisz wiedzieć, że programowanie funkcyjne nie jest nowym tworem. &lt;a href=&quot;https://pl.wikipedia.org/wiki/Rachunek_lambda&quot;&gt;Podstawy teoretyczne&lt;/a&gt; istnieją już od lat 30 ubiegłego wieku, a pierwsze języki funkcyjne powstały w tych samych czasach, co pierwsze języki imperatywne.&lt;/p&gt;

&lt;p&gt;Czym jest programowanie funkcyjne? Jest to po prostu podejście do pisania programów, w którym wszystkie rozwiązania problemów sprowadza się do zbudowania funkcji.
Jeżeli Twoją pierwszą myślą jest “przecież teraz też implementuję funkcje”, to masz rację. Różnica polega na tym, że:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;przypisujesz wartości do zmiennych,&lt;/li&gt;
  &lt;li&gt;implementujesz procedury (takie funkcje, tylko nie zwracające wartości),&lt;/li&gt;
  &lt;li&gt;sterujesz wykonaniem programu instrukcja po instrukcji.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;W podejściu funkcyjnym wszystko co robisz jest ubrane w funkcję. Wynik jednej funkcji musi być przekazany bezpośrednio do drugiej funkcji. Funkcja musi zwracać wartość.&lt;/p&gt;

&lt;p&gt;F# nie jest językiem funkcyjnym.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;/ Kurtyna /&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;f&quot;&gt;F#&lt;/h2&gt;

&lt;p&gt;F# jest hybrydą. Większość języka jest skonstruowana pod paradygmat funcyjny. Mamy jednak wszystkie konstrukcje, potrzebne do stworzenia obiektowego kodu.&lt;/p&gt;

&lt;p&gt;Kilka cech F# sprawia, że jest on doskonałym narzędziem do bezpiecznego programowania:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;statyczne typowanie z silną inferencją,&lt;/li&gt;
  &lt;li&gt;używa wyrażeń zamiast twierdzeń - funkcja zawsze zwraca wartość,&lt;/li&gt;
  &lt;li&gt;domyślnie operuje na wartościach niezmiennych (ang. &lt;em&gt;immutable&lt;/em&gt;),&lt;/li&gt;
  &lt;li&gt;używa typów opcjonalnych zamiast null,&lt;/li&gt;
  &lt;li&gt;pozwala na łatwe zwracanie niepoprawnego stanu zamiast operowania na wyjątkach.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Istotną cechą F# jest możliwość wykorzystania kodu napisanego w tym języku w dowolnych aplikacjach .NET. Interoperacyjność pozwala na wykorzystanie właścowości F# w tych miejscach, w których mają zdecydowaną przewagę nad kodem C#. Przykładami takich zastosowań jest implementacja skomplikowanych algorytmów oraz tworzenie wielowątkowego kodu.&lt;/p&gt;

&lt;p&gt;W kolejnych wpisach będę przybliżał poszczególne cechy F# i porównywał je z możliwościami języka C#.&lt;/p&gt;

</description>
        <pubDate>Mon, 15 Feb 2016 03:00:00 -0600</pubDate>
        <link>https://www.binarythoughts.pl/2016/02/fsharp-po-radosnej-stronie/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2016/02/fsharp-po-radosnej-stronie/</guid>
        
        <category>fsharp</category>
        
        <category>lang</category>
        
        
      </item>
    
      <item>
        <title>Dlaczego Java ssie?</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-why-java-sucks.jpg&quot; alt=&quot;Spilled coffee&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Ostatnio zdarzyło mi się wdać w jałową dyskusję na temat wyższości C# nad Javą. Padł tam koronny argument fanboya Javy, pt. “nie masz pojęcia o czym mówisz, nie używasz Javy”. Otóż, prawie. Od kilku miesięcy pracuję jako programista tego pokracznego języka. Postanowiłem wreszcie wylać swoje żale na wasze ekrany.&lt;/p&gt;

&lt;h2 id=&quot;gettery-i-settery&quot;&gt;Gettery i settery&lt;/h2&gt;

&lt;p&gt;Java, WTF? Rozumiem konwencję utrzymywania enkapsulacji pól i udostępniania/modyfikacji danych przez funkcje. Moje pytanie brzmi: skoro jest to praktycznie obowiązkowa część korzystania z języka i każdy framework wymaga stosowania się do tej zasady, to &lt;em&gt;dlaczego nie można było tego zmieścić do jednej linii?&lt;/em&gt; Zarządzanie kodem udekorowanym getterami i setterami to piekło.
Brak sensownego rozwiązania problemu getterów i setterów to tylko wierzchołek góry lodowej, jakim jest…&lt;/p&gt;

&lt;h2 id=&quot;brak-lukrów-składniowych&quot;&gt;Brak lukrów składniowych&lt;/h2&gt;

&lt;p&gt;Operujesz na kolekcji. Chcesz dostać jej pierwszy element. Co robisz? Oczywiście, wywołujesz metodę, zamiast zastosować stosowany w tablicach &lt;em&gt;operator []&lt;/em&gt;. Przyczyna jest prosta: nie można przeciążać operatorów. Właściwie wszystko co robisz musi być opisane słowem, nazwą metody.&lt;/p&gt;

&lt;p&gt;Takich przykładów jest mnóstwo. Aż dziw bierze, że ciągi znaków konkatenujemy &lt;em&gt;operatorem +&lt;/em&gt;, zamiast &lt;em&gt;.append()&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;deklarowanie-rzucanych-wyjątków&quot;&gt;Deklarowanie rzucanych wyjątków&lt;/h2&gt;

&lt;p&gt;Java wymaga zadeklarowania jakie wyjątki mogą zostać rzucone przez metodę. Wydaje się przydatne, prawda? Korzystając z danej metody, wiesz czego się spodziewać. Problem polega na tym, że kod jest organizmem żywym i zdarza się, że metoda, której używasz, zaczyna rzucać więcej wyjątków. Co się wtedy stanie? Ano dupa, Twój kod przestał się właśnie kompilować. Musisz obsłużyć sytuację albo dodać wyjątek do listy &lt;em&gt;throws&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Ok, załóżmy nawet, że API z którego korzystasz się nie zmienia. W Javie istnieje coś takiego, jak &lt;em&gt;RuntimeException&lt;/em&gt;. Wyjątek ten, jak i jego potomstwo nie muszą być zdefiniowane jako rzucane przez metodę. W ten sposób otrzymano konstrukcję językową, która nie daje żadnej pewnej informacji. Przynosi w zamian za to mnóstwo problemów z utrzymaniem kodu.&lt;/p&gt;

&lt;h2 id=&quot;zarządzanie-zależnościami&quot;&gt;Zarządzanie zależnościami&lt;/h2&gt;

&lt;p&gt;Napisałeś własną bibliotekę. Brawo! Korzystasz w niej z innej biblioteki. Dla uproszczenia, nazwijmy Twoją bibliotekę &lt;em&gt;BadassLib&lt;/em&gt;, a bibliotekę od której zależysz - &lt;em&gt;HaxxorLib&lt;/em&gt;. Pisząc swój kod korzystałeś z &lt;em&gt;HaxxorLib&lt;/em&gt; w wersji 2.1.0. W wersji 2.2.0 usunięta została jedna z metod, na której polegałeś. Przygotowałeś konfigurację &lt;em&gt;Mavena&lt;/em&gt; (taki javowy &lt;em&gt;NuGet&lt;/em&gt; + &lt;em&gt;msbuild&lt;/em&gt;), w której jasno określiłeś, że &lt;em&gt;BadassLib&lt;/em&gt; wymaga &lt;em&gt;HaxxorLib&lt;/em&gt; w wersji dokładnie 2.1.0. I co? Panu Ryszardowi spodobała się Twoja biblioteka i postanowił jej użyć. Niestety, w swoim projekcie nie korzysta z &lt;em&gt;Mavena&lt;/em&gt;. Dlaczego nie korzysta z &lt;em&gt;Mavena&lt;/em&gt;? Powodów może być wiele, nie chcę się nad nimi rozwodzić. Istotne jest to, w jaki sposób Pan Ryszard rozwiąże problem zależności &lt;em&gt;BadassLib&lt;/em&gt;. Otóż doda on do &lt;em&gt;classpatha&lt;/em&gt; ręcznie pobrany &lt;em&gt;HaxxorLib&lt;/em&gt;. Zgadnij w jakiej wersji &lt;em&gt;HaxxorLib&lt;/em&gt; była do pobrania ze strony biblioteki :-) Miłego debugowania, Panie Ryszardzie.&lt;/p&gt;

&lt;p&gt;Źródłem tego problemu jest beznadziejny system zarządzania zależnościami w środowisku Java. Decyzja o wykorzystaniu zależności podejmowana jest na podstawie &lt;em&gt;classpatha&lt;/em&gt;, a nie wymagań konkretnego modułu. Z tego powodu otrzymujemy piękne zjawisko, jakim jest &lt;a href=&quot;https://www.google.com/search?q=jar+hell&quot;&gt;Jar Hell&lt;/a&gt;. Problem ma zostać rozwiązany przez projekt Jigsaw, jednak na to &lt;a href=&quot;http://blog.takipi.com/jigsaw-delays-push-java-9-launch-date-to-2017/&quot;&gt;przyjdzie nam jeszcze długo poczekać&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;podsumowanie&quot;&gt;Podsumowanie&lt;/h2&gt;

&lt;p&gt;Nie chodzi o to, że język Java do niczego się nie nadaje. Po prostu jego składnia jest toporna i nie sprzyja czytaniu kodu, a zarządzanie zależnościami pozwala na nadużycia i prowadzi do trudnych do wykrycia błędów. Do tego dochodzi problem z niespójnością koncepcji. Możesz używać +operatora +_ na obiektach String, ale nie możesz ich wykorzystać w swojej klasie. Musisz stosować gettery i settery, ale nie możesz mieć ich skróconych do jednej linii. &lt;a href=&quot;https://youtu.be/7DMDscGOUpg?t=3m05s&quot;&gt;Same sprzeczności&lt;/a&gt;…&lt;/p&gt;
</description>
        <pubDate>Mon, 18 Jan 2016 03:00:00 -0600</pubDate>
        <link>https://www.binarythoughts.pl/2016/01/dlaczego-java-ssie/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2016/01/dlaczego-java-ssie/</guid>
        
        <category>devLife</category>
        
        <category>java</category>
        
        
      </item>
    
      <item>
        <title>Narzędzia programisty #1: Brackets</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-devtools-brackets.png&quot; alt=&quot;Customized Brackets&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Rozpoczynam nowy cykl na blogu. Co jakiś czas będę prezentował przydatne narzędzia, które ułatwiły moją pracę. W dzisiejszym odcinku mowa będzie o edytorze tekstu Brackets - open-sourcowym dziecku firmy Adobe.&lt;/p&gt;

&lt;h2 id=&quot;po-co-kolejny-edytor-tekstu&quot;&gt;Po co kolejny edytor tekstu?&lt;/h2&gt;

&lt;p&gt;Edytor tekstu, sam w sobie, nie jest niczym szczególnym. Narzędzia tego typu powstają od ponad 40 lat. Siła Bracketsa leży jednak w przejrzystości i użyteczności. Jako główne zalety podałbym:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;tekst jest czytelny i nie męczy oczu,&lt;/li&gt;
  &lt;li&gt;standardowe kolory są idealnie dobrane,&lt;/li&gt;
  &lt;li&gt;interfejs jest przejrzysty,&lt;/li&gt;
  &lt;li&gt;opcja live preview pozwana na podgląd projektowanej strony WWW na żywo (a’la Browser Link z Visual Studio),&lt;/li&gt;
  &lt;li&gt;system rozszerzeń pozwala na bardzo duże modyfikacje, jednocześnie uniemożliwiając popsucie UX.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;edytor-miły-dla-oka&quot;&gt;Edytor miły dla oka&lt;/h2&gt;

&lt;p&gt;Czcionki i kolory mogą wydawać się błahostką. Sprawiają jednak, że długie korzystanie z narzędzia jest (lub nie jest) przyjemne. To samo dotyczy interfejsu. Dodatkowe okna w każdym miejscu środowiska prowadzą do dekoncentracji. Brackets wygrywa w tej kategorii. Oczywiście w VS, Sublime Text czy Atomie mogę również zmienić kompozycję i kolorystykę. Jednak powiedzmy sobie szczerze: dostępne modyfikacje zwykle wyglądają paskudnie.&lt;/p&gt;

&lt;p&gt;Który tekst jest czytelniejszy?&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-devtools-brackets-brackets-ui-text.jpg&quot; alt=&quot;Adobe Brackets - fragment kodu JSON&quot; width=&quot;466&quot; height=&quot;378&quot; /&gt;
&lt;figcaption&gt;Adobe Brackets - fragment kodu JSON&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
    &lt;img src=&quot;/images/post-devtools-brackets-atom.jpg&quot; alt=&quot;Github Atom - fragment kodu CSON&quot; width=&quot;470&quot; height=&quot;330&quot; /&gt;
&lt;figcaption&gt;Github Atom - fragment kodu CSON&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Oczywiście takie przykłady można mnożyć.&lt;/p&gt;

&lt;h2 id=&quot;rozszerzenia&quot;&gt;Rozszerzenia&lt;/h2&gt;

&lt;p&gt;Czysta instalacja Bracketsa jest dość mało rozbudowana. Na szczęście mamy rozszerzenia. Zmieniają one prosty edytor tekstu w pełnoprawne IDE.&lt;/p&gt;

&lt;p&gt;Nie będę wymieniał dostępnych rozszerzeń. Nie brakuje praktycznie niczego. A w każdym razie ja nie potrzebowałem rzeczy, do których nie było plugina.&lt;/p&gt;

&lt;p&gt;Trafiłeś na coś, czego brakuje? Obecne rozszerzenie posysa? Napisz własne lub popraw istniejące. To naprawdę proste. Brackets jest w rzeczywistości oknem przeglądarki. Oznacza to tyle, że edytor i wtyczki są połączeniem plików JavaScript, HTML i CSS. Podstawowe API jest proste i nawet żółtodziób &lt;a href=&quot;https://github.com/dalcib/brackets-gulp/pulls?q=is%3Apr+is%3Aclosed&quot;&gt;poradzi sobie z pisaniem rozszerzeń&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;omnisharp&quot;&gt;OmniSharp&lt;/h2&gt;

&lt;p&gt;Przyszedł czas na zabawkę dla niegrzecznych programistów. Tych od czarnych korpo-technologii .NET.&lt;/p&gt;

&lt;p&gt;Microsoft postawił ostatnio na wieloplatformowość i niezależność od &lt;em&gt;Visual Studio&lt;/em&gt;. Słyszałeś o projekcie &lt;em&gt;OmniSharp&lt;/em&gt;? Jest to zbiór wtyczek do popularnych edytorów tekstu. Owe wtyczki mają za zadanie dostarczyć środowisko do pracy z C#.&lt;/p&gt;

&lt;p&gt;Dobra wiadomość jest taka, że OmniSharp dla Bracketsa istnieje. Zła - jest mało rozbudowany. Obecnie pozwala jedynie na formatowanie kodu i usunięcie nieużywanych importów (using). Na domiar złego, wersja w repozytorium rozszerzeń Bracketsa jest nieaktualna. Trzeba ją pobrać z repozytorium do katalogu wtyczek.&lt;/p&gt;

&lt;p&gt;Istnieje kilka problemów podowanych przez pracę poza Visual Studio:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;budowanie aplikacji i uruchamianie testów jest problematyczne,&lt;/li&gt;
  &lt;li&gt;opcje refactorowania i debugowania są mocno ograniczone,&lt;/li&gt;
  &lt;li&gt;nie ma narzędzi do profilowania wydajności.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jeśli chodzi o budowanie i uruchamianie testów, sprawa jest prosta. Obydwa procesy można wykonywać poprzez proste skrypty. W ASP.NET 5 jest to szczególnie ułatwione - wszystko uruchamia się za pomocą polecenia &lt;em&gt;k&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Brak możliwości debugowania i profilowania psuje zabawę. Częściowo można zastąpić oba procesy pisząc testy. No właśnie, częściowo…&lt;/p&gt;

&lt;h2 id=&quot;co-dalej&quot;&gt;Co dalej?&lt;/h2&gt;

&lt;p&gt;Edytor możesz &lt;a href=&quot;http://brackets.io/&quot;&gt;pobrać ze strony projektu&lt;/a&gt;. Jeżeli jesteś webdeveloperem z .NETowym zapleczem i zależy Ci na narzędziach niezależnych od Visual Studio, spróbuj wspomóc rozwój &lt;a href=&quot;https://github.com/OmniSharp/omnisharp-brackets&quot;&gt;omnisharp-brackets&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Mon, 09 Mar 2015 08:00:00 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2015/03/narzedzia-brackets/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2015/03/narzedzia-brackets/</guid>
        
        <category>frontend</category>
        
        <category>webdev</category>
        
        <category>toolsSeries</category>
        
        
      </item>
    
      <item>
        <title>Jekyll: ucieczka od Wordpressa</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-jekyll.jpg&quot; alt=&quot;Dr. Jekyll&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;W życiu każdego bloggera przychodzi taki moment, w którym zaczyna blogować o blogowaniu. U mnie wypada to teraz. Jak pewnie zauważyliście, na blogu nastąpiły drobne zmiany stylistyczne. Pod maską natomiast zmiany są drastyczne: przeniosłem wszystko na platformę Jekyll.&lt;/p&gt;

&lt;h2 id=&quot;czym-jest-jekyll&quot;&gt;Czym jest Jekyll?&lt;/h2&gt;

&lt;p&gt;Jekyll jest frameworkiem do blogowania. Różni się jednak od klasycznych narzędzi tego typu. Cała treść generowana jest po stronie autora strony, a na serwer trafiają jedynie statyczne pliki. Nie ma tu żadnej bazy danych, dziurawych pluginów i ponownego generowania tej samej treści.&lt;/p&gt;

&lt;p&gt;Zlikwidowanie wartwy aplikacji webowej wydaje się cofnięciem o 20 lat w rozwoju. Ma to jednak wymierne korzyści:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;zmniejszamy powierzchnię ataku&lt;/li&gt;
  &lt;li&gt;zwiększamy wydajność strony&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Z miejsca eliminujemy błędy związane z uwierzytelnianiem, autoryzacją, kontrolą sesji użytkownika, wstrzykiwaniem kodu (SQLi, RCI), międzydomenowym fałszowaniem żądań (CSRF) i pewnie wiele innych. Oczywiście możemy zwiększyć ponownie powierzchnię ataku, odbierając dane od użytkownika, jednak w większości przypadków związanych z blogowaniem jest to po prostu zbędne.&lt;/p&gt;

&lt;p&gt;Jednocześnie usuwamy wąskie gardła – komunikację aplikacji z bazą danych i innymi zasobami sieciowymi. Statyczne pliki mają jeszcze jedną zaletę: serwer WWW kompresuje je znacznie wydajniej niż treść generowaną dynamicznie. W moim przypadku czas łączny ładowania strony głównej zmniejszył się o 2/3.&lt;/p&gt;

&lt;h2 id=&quot;layouty-wpisy-i-metadane&quot;&gt;Layouty, wpisy i metadane&lt;/h2&gt;

&lt;p&gt;Layout i treść strony generowane są z plików HTML i MarkDown przez silnik Liquid. Wygląda to podobnie do widoków w ASP.NET MVC. Istnieją tu koncepcje layout, view, partial view etc. Są po prostu inaczej nazwane.
Największa wada? Nie ma gotowych layoutów. Największa zaleta? Nie ma gotowych layoutów.&lt;/p&gt;

&lt;p&gt;Wordpress jest świetny do szybkiego rozpoczęcia przygody z pisaniem. Niestety, layouty zwykle są marnej jakości i nie są responsywne. Jakby tego było mało, do każdej pierdoły potrzebny jest plugin, który jeszcze bardziej psuje strukturę plików HTML i CSS. Spotkałem się z pluginami doklejającymi wszystkie swoje style w treść HTML. Za każdym przeładowaniem strony konieczne było pobranie na nowo tych samych stylów.&lt;/p&gt;

&lt;p&gt;Wersja dla leniwych jest prosta – możemy skorzystać ze standardowego layoutu Jekylla.&lt;/p&gt;

&lt;p&gt;Jak już wspomniałem, wpisy trzymamy w plikach HTML/MarkDown. Metadane przechowywane są razem z treścią wpisu, na samej górze dokumentu. Mają postać dokumentu YAML.&lt;/p&gt;

&lt;h2 id=&quot;serve-i-build&quot;&gt;Serve i Build&lt;/h2&gt;

&lt;p&gt;Jekyll posiada dwa polecenia służące do kompilowania projektu do statycznej strony:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;jekyll build&lt;/li&gt;
  &lt;li&gt;jekyll serve&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Build wykonuje jednorazową przebudowę projektu. Serve buduje projekt i czeka na zmiany w plikach projektu.&lt;/p&gt;

&lt;h2 id=&quot;instalacja-środowiska-windows&quot;&gt;Instalacja środowiska (Windows)&lt;/h2&gt;

&lt;p&gt;Najpierw instalujemy manager pakietów Chocolatey. Chocolatey można porównać do apt-get z systemów GNU/Linux lub Homebrew z Mac OS. Uruchamiamy polecenie:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;@powershell &lt;span class=&quot;nt&quot;&gt;-NoProfile&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ExecutionPolicy&lt;/span&gt; unrestricted &lt;span class=&quot;nt&quot;&gt;-Command&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; SET &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;%PATH%&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;%ALLUSERSPROFILE%&lt;span class=&quot;se&quot;&gt;\c&lt;/span&gt;hocolatey&lt;span class=&quot;se&quot;&gt;\b&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Następnie instalujemy wszystkie niezbędne paczki oraz gemy. Gemy są paczkami języka Ruby. &lt;strong&gt;Uruchamiamy ponownie konsolę&lt;/strong&gt; i wpisujemy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;choco &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;git ruby ruby2.devkit 7zip.commandline
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; - C:/tools/ruby215&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; C:/tools/DevKit2/config.yml &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;C:/tools/DevKit2 &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ruby dk.rb &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ..
@powershell &lt;span class=&quot;nt&quot;&gt;-NoProfile&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ExecutionPolicy&lt;/span&gt; unrestricted &lt;span class=&quot;nt&quot;&gt;-Command&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;iex ((new-object System.Net.WebClient).DownloadFile('https://github.com/rubygems/rubygems/archive/v2.4.6.zip','rubygems-2.4.6.zip'))&quot;&lt;/span&gt;
7za x rubygems-2.4.6.zip &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;rubygems-2.4.6 &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ruby setup.rb &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; .. &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rd /s /q rubygems-2.4.6 &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; del /s /q rubygems-2.4.6.zip&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ponownie &lt;strong&gt;restartujemy konsolę&lt;/strong&gt; i wpisujemy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;jekyll rouge&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Przechodzimy do wybranego katalogu i tworzymy nowy projekt Jekylla:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;jekyll new appName
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;appName
&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;highlighter: rouge&amp;gt;&amp;gt; _config.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Możemy uruchomić aplikację:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;jekyll serve&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;W tym momencie pod adresem http://localhost:4000 działa statyczna strona WWW z przykładowym wpisem. Każda zmiana w plikach projektu spowoduje natychmiastową przebudowę projektu.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Uwaga: plik _config.yml jest ładowany jednorazowo. Żeby załadować go ponownie, wymagane jest ponowne uruchomienie polecenia jekyll serve.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;import-bloga-z-wordpressa&quot;&gt;Import bloga z Wordpressa&lt;/h2&gt;

&lt;p&gt;Na początek wymieńmy rzeczy, które można zaimportować:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;wpisy,&lt;/li&gt;
  &lt;li&gt;statyczne strony,&lt;/li&gt;
  &lt;li&gt;metadane wpisów i stron.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Oznacza to tyle, że nie ma możliwości automatycznego przeniesienia layoutu, o czym wspominałem wcześniej.&lt;/p&gt;

&lt;p&gt;Proces importowania zaczynamy od instalacji niezbędnych gemów:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;sequel fileutils safe_yaml unidecode mysql2 htmlentities jekyll-import&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Przechodzimy do katalogu utworzonego wcześniej projektu. Następnie tworzymy plik &lt;em&gt;import.rb&lt;/em&gt;. Wstawiamy do niego dane do Wordpressa:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;jekyll-import&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;JekyllImport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Importers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;WordPress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;dbname&quot;&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;user&quot;&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;password&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;host&quot;&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;socket&quot;&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;table_prefix&quot;&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;wp_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;clean_entities&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;comments&quot;&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;categories&quot;&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;tags&quot;&lt;/span&gt;           &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;more_excerpt&quot;&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;more_anchor&quot;&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;status&quot;&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;publish&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Teraz uruchamiamy skrypt:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;ruby &lt;span class=&quot;nt&quot;&gt;-rubygems&lt;/span&gt; import.rb&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Po wykonaniu importu warto przejrzeć zawartość plików &lt;em&gt;.markdown&lt;/em&gt; i poprawić ewentualne błędy. Przydatna będzie funcja znajdź i zastąp. ;-)&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Materiały dodatkowe&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://jekyllrb.com/docs/home/&quot;&gt;Jekyll: Dokumentacja&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://import.jekyllrb.com/docs/home/&quot;&gt;Jekyll-import: Dokumentacja&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://jekyll-windows.juthilo.com/&quot;&gt;Run Jekyll on Windows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 23 Feb 2015 09:00:00 -0600</pubDate>
        <link>https://www.binarythoughts.pl/2015/02/jekyll-ucieczka-od-wordpressa/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2015/02/jekyll-ucieczka-od-wordpressa/</guid>
        
        <category>jekyll</category>
        
        
      </item>
    
      <item>
        <title>ASP.NET 5</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-aspnet-5.jpg&quot; alt=&quot;Super Doge&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Nadchodzi król. Jedenastego listopada &lt;a title=&quot;ASP.NET MVC 6.0.0-beta1&quot; href=&quot;https://www.nuget.org/packages/Microsoft.AspNet.Mvc/6.0.0-beta1&quot; target=&quot;_blank&quot;&gt;została wydana &lt;/a&gt;pierwsza beta ASP.NET 5.&lt;/p&gt;

&lt;h2&gt;O co chodzi?&lt;/h2&gt;
&lt;p&gt;Microsoft realizuje &lt;a title=&quot;O tym, dlaczego nie powinno się przepisywać aplikacji od podstaw&quot; href=&quot;http://www.joelonsoftware.com/articles/fog0000000069.html&quot; target=&quot;_blank&quot;&gt;szalony pomysł&lt;/a&gt;. Zespół ASP.NET przepisuje frameworki MVC, Web API oraz Web Pages, a dokładniej łączy je w jedną całość. Mało tego, że przepisuje. Otwiera kod źródłowy i na bieżąco słucha głosu programistów. Możesz na bieżąco sprawdzać postęp w tworzeniu frameworka ASP.NET 5, testować nowe wersje i zgłaszać błędy (lub pomysły). Całość toczy się na &lt;a title=&quot;ASP.NET 5 - GitHub&quot; href=&quot;https://github.com/aspnet/&quot; target=&quot;_blank&quot;&gt;GitHubie&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Moloch w kawałkach, czyli budowa ASP.NET 5&lt;/h2&gt;
&lt;p&gt;W zamierzchłych czasach ASP.NET był częścią .NET Framework. Jeżeli oczekiwałeś nowości - aktualizowałeś cały .NET. Jeżeli WinFormsy były łatane - aktualizowałeś cały .NET. Przypadkiem mogli przecież dołożyć zmiany w ASP.NET (konia z rzędem temu, kto czyta opisy poprawek). Wszystko było ciężkie i mało zwinne. Na szczęście sytuacja od dawna wygląda inaczej. ASP.NET MVC i jego pochodne są serwowane jako pakiety NuGet. Niestety, niektóre zależności w dalszym ciągu są częścią platoformy .NET. Cały stos ASP.NETa jest oparty o bibliotekę &lt;em&gt;System.Web&lt;/em&gt;. Zawiera ona wszystko, czego mógłbyś(mogłabyś) użyć przy pisaniu aplikacji internetowej. Problem w tym, że nie użyjesz. Otrzymujesz ciężkie obiekty, które zapychają pamięć. &lt;strong&gt;ASP.NET 5 nie korzysta z &lt;em&gt;System.Web!&lt;/em&gt;&lt;/strong&gt; Nie będę tęsknił.&lt;/p&gt;

&lt;p&gt;W ASP.NET 5 wszystko, z czego chcemy skorzystać musi zostać jawnie zadeklarowane.Najbardziej charakterystycznym przykładem jest włączenie serwowania statycznych plików (whaaat!?).&lt;/p&gt;

&lt;h2&gt;K-da fuq?&lt;/h2&gt;
&lt;p&gt;Nowy ASP.NET niesie ze sobą nowe narzędzia i środowiska uruchomieniowe. Pierwszym ich zbiorem jest &lt;strong&gt;Project K&lt;/strong&gt;. Składa się z kilku elementów:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;kre - (K Runtime Environment) - środowisko uruchomieniowe dla aplikacji ASP.NET 5, obsługuje proces budowania aplikacji,&lt;/li&gt;
    &lt;li&gt;kvm (K Version Manager) - program zarządzający wersjami kre (pierwsza rzecz do pobrania),&lt;/li&gt;
    &lt;li&gt;k - polecenie uruchamiające skonfigurowane skrypty (np. &lt;em&gt;k web&lt;/em&gt; uruchamia aplikację w trybie &lt;em&gt;self-hosted&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Interesujący jest fakt, że wersję KRE wybierasz dla projektu, nie dla wszystkich aplikacji na maszynie. Jeżeli piszesz swoją aplikację w Visual Studio i uruchamiasz na serwerze IIS, możesz nawet nie zauważyć różnicy. Co innego, gdy tworzysz program za pomocą vima (:q) na Arch Linux.&lt;/p&gt;

&lt;h2&gt;Wiele systemów, wiele środowisk programistycznych&lt;/h2&gt;
&lt;p&gt;Tak, nie pomyliłeś(-aś) się czytając nagłówek. ASP.NET 5 działa na Windowsie, Macu i GNU/Linux. W przypadku Windowsa możesz użyć serwera IIS lub uruchomić aplikację jako self-hosted. Na pozostałych systemach pozostaje Ci tylko druga opcja (za pomocą miniserwera &lt;em&gt;Kestrel;&lt;/em&gt; możesz też poczekać na jakiś sensowny serwer/mod do nginxa).&lt;/p&gt;

&lt;p&gt;Według mnie, istotniejsza jest możliwość wyboru IDE. Visual Studio jest prawdziwym kombajnem. Nadaje się całkiem nieźle, jeżeli całą aplikację robisz samodzielnie (albo każdy programista robi wszystko po trochu). Problem pojawia się, gdy jesteś front-end developerem i nie potrzebujesz budowania całej aplikacji w ciężkim środowisku, jakim jest VS. Chcesz tylko co jakiś czas pobrać kod z repozytorium i sprawdzić, czy koledzy z zespołu nie popsuli modelu danych, które odbierasz. W takiej sytuacji możesz korzystać z Sublime Text + &lt;a title=&quot;Wspomagacz dla zestawu ASP.NET 5 + Sublime Text&quot; href=&quot;https://sublime.wbond.net/packages/Kulture&quot; target=&quot;_blank&quot;&gt;Kulture&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Nowa struktura projektu&lt;/h2&gt;
&lt;p&gt;Pamiętasz bałagan w projektach ASP.NET MVC? JavaScript, CSS i obrazki rozrzucone po kilku miejscach? Od teraz wszystkie statyczne elementy statyczne będziesz wrzucał(-a) do katalogu &lt;em&gt;wwwroot&lt;/em&gt;. Co prawda widoki są oddzielone od załączanej do nich treści, ale daje to dość dobry rezultat. Kolejną zmianą jest podział projektu na źródła (/src) i testy (/test). Prawdę mówiąc wolałbym sortowanie projektów wg typu, ale dzięki dodaniu nowego poziomu hierarchii możliwa jest praca w dowolnym środowisku.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-aspnet-5-vnext-structure.png&quot; alt=&quot;Struktura projektu ASP.NET 5&quot; width=&quot;233&quot; height=&quot;347&quot; /&gt;
&lt;figcaption&gt;Struktura projektu ASP.NET 5&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2&gt;Node.js w ASP.NET&lt;/h2&gt;
&lt;p&gt;ASP.NET 5 korzysta z narzędzi takich jak:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;NPM (Node Package Manager) - zarządca pakietów napisanych w Node.js/JavaScripcie,&lt;/li&gt;
    &lt;li&gt;Bower - zarządca pakietów dla aplikacji internetowych,&lt;/li&gt;
    &lt;li&gt;Grunt - program automatyzujący zadania front-endowe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;W dużym skrócie: za pomocą Bowera ściągamy front-endowe zależności takie jak Angular.js, Knockout etc. etc. Za pomocą Grunta uruchamiamy zadania, np. kompilacja TypeScript -&amp;gt; JavaScript, LESS -&amp;gt; CSS. NPM służy do pobrania Bowera, Grunta i gotowych skryptów dla Grunta.&lt;/p&gt;

&lt;p&gt;Dzięki użyciu Bowera, zależności front-endowe i back-endowe zostały rozdzielone. Na obrazku wyżej jest to wyraźnie widoczne: front-endowe zależności w &lt;em&gt;Dependencies&lt;/em&gt;, back-endowe w &lt;em&gt;References&lt;/em&gt;. Dla back-endu w dalszym ciągu używać będziesz NuGeta.&lt;/p&gt;

&lt;h2&gt;Nowa wersja czy nowy framework?&lt;/h2&gt;
&lt;p&gt;Patrząc na ogromną liczbę zmian możesz dojść do wniosku, że powstał zupełnie nowy framework. Na szczęście nie wszystko zostało porzucone. Idea modeli, widoków i kontrolerów pozostała taka sama. Możliwe jest więc przeportowanie starej aplikacji MVC 5 na ASP.NET 5. Oczywiście nie obejdzie się bez zmian w kodzie. W szczególności czekam na nowe podejście do procesu uwierzytelniania i autoryzacji użytkowników.&lt;/p&gt;

&lt;h2&gt;Kiedy pełna wersja?&lt;/h2&gt;
&lt;p&gt;Podczas dotnetConf 2014 &lt;a title=&quot;ASP.NET MVC 6 - dotNetConf 2014&quot; href=&quot;http://channel9.msdn.com/Events/dotnetConf/2014/MVC-6&quot; target=&quot;_blank&quot;&gt;Daniel Roth wspomniał&lt;/a&gt; o terminie wydania wersji RTM. Microsoft planuje wydanie na pierwszy kwartał 2015 roku. Daje to niewiele ponad 4 miesiące od teraz. Zobaczymy czy dadzą radę. Osobiście im kibicuję. Zaplanowałem nawet oparcie pracy magisterskiej o nowy framework ;-)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Posłowie&lt;/strong&gt;&lt;br /&gt;
O kilku rzeczach nie wspomniałem.&lt;/p&gt;

&lt;p&gt;Pierwsza sprawa - kod ASP.NET MVC był od dawna publiczny. Nie było jednak możliwości współpracy przy jego tworzeniu. Microsoft dał możliwość dołożenia własnych cegiełek do projektu za pomocą mechanizmu pull requestów i issue trackera. Nowością jest też rozwijanie oprogramowania w czasie bliskim rzeczywistemu - nowe zmiany pojawiają się niemalże każdego dnia.&lt;/p&gt;

&lt;p&gt;Druga sprawa - mam nadzieję, że zespół ASP.NETa się opamięta i zmieni nazwę projektu K. Już wyobrażam sobie szukanie rozwiązań za pomocą Google, StackOverflow etc.
Trzecia sprawa - nawet, jeśli jesteś front-end developerem, zastanów się nad pisaniem aplikacji w Visual Studio. BrowserLink + Web Essentials dają niesamowitego kopa. Wygląd aplikacji możesz tworzyć/poprawiać w przeglądarce za pomocą narzędzi developerskich.&lt;/p&gt;

&lt;p&gt;Na koniec uwaga co do samej nazwy frameworka. W tej chwili Microsoft przeplata kilka nazw tego samego: ASP.NET 5, ASP.NET MVC 6, ASP.NET vNext. Wybrałem pierwsze ze względu na fakt, że zmianie nie ulega sam framework MVC. Zmienia się cały ekosystem.&lt;/p&gt;
</description>
        <pubDate>Mon, 24 Nov 2014 00:00:28 -0600</pubDate>
        <link>https://www.binarythoughts.pl/2014/11/asp-net-5/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2014/11/asp-net-5/</guid>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>ASP.NET 5 + Raspberry Pi</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-aspnet-vnext-raspberry-pi.png&quot; alt=&quot;K Version Manager&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Dzisiejszy odcinek jest sponsorowany przez problem zarządzania prywatnymi finansami. Wpadłem na pomysł zrobienia usługi + aplikacji klienckich (Web i Windows Phone) do zbierania danych o moich wydatkach. Mogłem oczywiście sprawę rozwiązać Excelem. Przeklikiwanie arkusza na telefonie nie należy jednak do najprzyjemniejszych rzeczy.&lt;/p&gt;

&lt;p&gt;Rozważałem napisanie usługi w pythonie, jednak chciałem sprawdzić nowości na platformie firmy Microsoft. Ostatecznie wybór padł na ASP.NET vNext. Nowa wersja ASP.NET ma ogromną zaletę - łączy usługi Web API ze stronami WWW frameworka MVC. Dzięki temu, jestem w stanie napisać usługę REST i aplikację WWW opartą o &lt;em&gt;Angular.js&lt;/em&gt; w jednym projekcie. Aplikacja będzie działała w trybie &lt;em&gt;self-hosted&lt;/em&gt; na Raspberry Pi.&lt;/p&gt;

&lt;h2&gt;Czym jest ASP.NET 5?&lt;/h2&gt;
&lt;p&gt;W dużym skrócie, ASP.NET 5 (vNext) jest:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;przyszłą, pisaną od nowa, wersją ASP.NET MVC (6),&lt;/li&gt;
    &lt;li&gt;połączeniem &lt;em&gt;ASP.NET MVC&lt;/em&gt;, &lt;em&gt;ASP.NET Web API&lt;/em&gt; i &lt;em&gt;ASP.NET Web Pages&lt;/em&gt;,&lt;/li&gt;
    &lt;li&gt;otwartym kawałkiem kodu, który &lt;a title=&quot;ASP.NET vNext Github&quot; href=&quot;https://github.com/aspnet/home&quot; target=&quot;_blank&quot;&gt;możemy dowolnie edytować&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jedną z większych zalet ASP.NET 5 jest wieloplatformowość - aplikacje mogą być uruchamiane zarówno na Windowsie, jak i systemach GNU/Linux czy Mac OS X. Co istotne, wszystkie platformy są oficjalnie wspierane przez Microsoft.&lt;/p&gt;

&lt;h2&gt;Dlaczego Raspberry Pi?&lt;/h2&gt;
&lt;p&gt;Raspberry Pi było akurat pod ręką. Miniaturowy komputer leżał nieużywany w szafie i czekał aż z niego skorzystam. Miał służyć jako multimedialny hub, ostatecznie jednak postawiłem na usługi zewnętrzne (&lt;a title=&quot;Spotify&quot; href=&quot;https://www.spotify.com&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;Spotify&lt;/em&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;Instalacja pakietów&lt;/h2&gt;
&lt;p&gt;Zanim rozpoczniemy właściwą instalację, potrzebujemy kilkunastu pakietów. Większość z nich to zależności &lt;em&gt;mono&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;UWAGA: Moje Raspberry Pi działa pod kontrolą Raspbiana. Jeżeli posiadasz inny system operacyjny (np. Pidora), być może będziesz musiał/a skorzystać z innego managera pakietów (yum, pacman etc.).&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Logujemy się przez SSH na Raspberry Pi.&lt;/li&gt;
  &lt;li&gt;Aktualizujemy repozytorium pakietów:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;3&quot;&gt;
    &lt;li&gt;Pobieramy niezbędne pakiety:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev build-essential git-core automake libtool libglib2.0-dev libxrender-dev libfontconfig1-dev libpng12-dev libgif-dev libjpeg8-dev libtiff5-dev libexif-dev mono-complete screen lynx&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2&gt;GNU Screen&lt;/h2&gt;
&lt;p&gt;Kompilacja mono trwa kilka godzin. W razie zerwania sesji SSH, proces zostanie przerwany. Rozwiązaniem jest wykonywanie poleceń w sesji &lt;em&gt;screen&lt;/em&gt;. &lt;em&gt;GNU Screen&lt;/em&gt; jest programem utrzymującym uruchomione zadania po wylogowaniu użytkownika. Posiada też inne zastosowania (podobno ktoś z nich korzysta).
Uruchomienie nowej sesji sprowadza się do wykonania:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;screen &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; mono&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Odłączamy się od sesji za pomocą skrótu &lt;em&gt;CTRL + A&lt;/em&gt;, &lt;em&gt;D&lt;/em&gt;. Po tej operacji możemy bez problemu się wylogować. Aby przywrócić odpiętą sesję, wystarczy wpisać:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;screen &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; mono&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Voila. Możemy spokojnie odłączyć się od RPi w trakcie kompilacji.&lt;/p&gt;

&lt;h2&gt;Instalacja mono&lt;/h2&gt;
&lt;p&gt;Wszystko gotowe, czas zainstalować środowisko uruchomieniowe&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Ściągamy najnowsze źródła mono:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;git clone git://github.com/mono/mono.git&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;2&quot;&gt;
    &lt;li&gt;Przechodzimy do repozytorium:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;mono&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;3&quot;&gt;
    &lt;li&gt;Uruchamiamy konfigurator &lt;em&gt;autogen&lt;/em&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; ./autogen.sh &lt;span class=&quot;nt&quot;&gt;-prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/local &lt;span class=&quot;nt&quot;&gt;-enable-nls&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;no&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;&lt;a title=&quot;Raspberry Pi Mono 3.2+ Installation Hard Float Compatible&quot; href=&quot;http://c-mobberley.com/wordpress/2013/12/27/raspberry-pi-mono-3-2-installation-hard-float-compatible/&quot; target=&quot;_blank&quot;&gt;&lt;u&gt;Plotki mówią&lt;/u&gt;&lt;/a&gt;, że zamiast parametru -prefix/-enable-nls, konieczne może być użycie .prefix/.enable-nls.&lt;/em&gt;&lt;/p&gt;

&lt;ol start=&quot;4&quot;&gt;
    &lt;li&gt;Ściągamy binarkę mini-kompilatora C# &lt;em&gt;monolite&lt;/em&gt; (część mono jest napisana w C#; żeby skompilować mono, musimy najpierw posiadać mono ;-))&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;make get-monolite-latest&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;5&quot;&gt;
    &lt;li&gt;&lt;strong&gt;Kompilujemy mono&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;make &lt;span class=&quot;nv&quot;&gt;EXTERNAL_MCS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PWD&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/mcs/class/lib/monolite/gmcs.exe&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;6&quot;&gt;
    &lt;li&gt;&lt;strong&gt;Instalujemy mono&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;7&quot;&gt;
    &lt;li&gt;Sprawdzamy, czy wszystko poszło zgodnie z planem...&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mono &lt;span class=&quot;nt&quot;&gt;-V&lt;/span&gt;
Mono JIT compiler version 3.10.1 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;master/8d9f05e czw, 23 paź 2014, 20:16:10 CEST&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Super; możemy odpalić pierwszy program!&lt;/p&gt;

&lt;ol start=&quot;8&quot;&gt;
    &lt;li&gt;Uruchamiamy testowy program:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'namespace Test { public static class TestClass { public static void Main() { System.Console.WriteLine(&quot;Hello, Mono!&quot;); } } } '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Main.cs
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo chmod&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; Main.cs
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mcs Main.cs
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mono Main.exe
Hello, Mono!&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Jak widać, wszystko przebiegło pomyślnie. Możemy kompilować programy przeznaczone na platformę .NET 4.5 i niższe.&lt;/p&gt;

&lt;h2&gt;Instalacja ASP.NET vNext&lt;/h2&gt;
&lt;p&gt;Centralnym punktem frameworka ASP.NET vNext jest menedżer wersji &lt;em&gt;kvm&lt;/em&gt; (&lt;em&gt;K Version Manager&lt;/em&gt;). Za jego pomocą instalujemy różne wersje frameworka, a także przełączamy się między nimi.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Instalujemy &lt;em&gt;kvm&lt;/em&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.sh | sh &amp;amp;amp&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&amp;amp;amp&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; ~/.kre/kvm/kvm.sh&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;2&quot;&gt;
    &lt;li&gt;Przechodzimy do repozytorium:&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
  &lt;li&gt;Instalujemy najnowsze &lt;em&gt;kre&lt;/em&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;kvm upgrade&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2&gt;Wielki test&lt;/h2&gt;
&lt;p&gt;W celu sprawdzenia konfiguracji naszego nowego serwera ASP.NET vNext, uruchomimy prostą aplikację.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Ściągamy repozytorium:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone https://github.com/Keraxel/MvcNext.git &amp;amp;amp&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&amp;amp;amp&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;MvcNext&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;2&quot;&gt;
    &lt;li&gt;Dodajemy certyfikaty (są &lt;a title=&quot;Hello new K world: kpm restore fail part 1.&quot; href=&quot;http://itofinity.wordpress.com/2014/06/04/hello-new-k-world-kpm-restore-fail-part-1/&quot; target=&quot;_blank&quot;&gt;niezbędne do pobrania zależności&lt;/a&gt;):&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;certmgr &lt;span class=&quot;nt&quot;&gt;-ssl&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; https://go.microsoft.com
y
y
y
y
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;certmgr &lt;span class=&quot;nt&quot;&gt;-ssl&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; https://nugetgallery.blob.core.windows.net
y
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;certmgr &lt;span class=&quot;nt&quot;&gt;-ssl&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; https://nuget.org
y
y
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mozroots &lt;span class=&quot;nt&quot;&gt;--import&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--sync&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;3&quot;&gt;
    &lt;li&gt;Uzupełniamy zależności projektu:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;~/MvcNext &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;kpm restore &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; https://www.myget.org/F/aspnetvnext/ &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; https://nuget.org/api/v2/
~/MvcNext &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; ~/.kpm/packages/Microsoft.AspNet.Server.Kestrel/1.0.0-alpha4/native/darwin/universal/libuv.dylib ~/.kpm/packages/Microsoft.AspNet.Server.Kestrel/1.0.0-alpha4/native/darwin/universal/libuv.dylib.backup
~/MvcNext &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;libuv.so.1 ~/.kpm/packages/Microsoft.AspNet.Server.Kestrel/1.0.0-alpha4/native/darwin/universal/libuv.dylib&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;4&quot;&gt;
    &lt;li&gt;&lt;strong&gt;Uruchamiamy projekt&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;~/MvcNext &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;MvcNext
~/MvcNext/MvcNext &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;k kestrel
Started&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Działa! Możemy wejść do aplikacji: http://[ip]:5004/Users.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-aspnet-vnext-raspberry-pi-rpi-kestrel.png&quot; alt=&quot;Aplikacja ASP.NET vNext na Raspberry Pi (Kestrel)&quot; width=&quot;1024&quot; height=&quot;768&quot; /&gt;
&lt;figcaption&gt;Aplikacja ASP.NET vNext na Raspberry Pi&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Do aplikacji można się dostać również poprzez przeglądarkę Lynx, bezpośrednio na Raspberry Pi:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;lynx http://[ip]:5004/Users&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;W następnym wpisie napiszę o samym ASP.NET vNext: zmianach, nowościach i niespodziankach, które zaserwował Microsoft.&lt;/p&gt;
</description>
        <pubDate>Sat, 25 Oct 2014 09:40:12 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2014/10/asp-net-vnext-raspberry-pi/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2014/10/asp-net-vnext-raspberry-pi/</guid>
        
        <category>aspnet</category>
        
        <category>raspberryPi</category>
        
        
      </item>
    
      <item>
        <title>Bundler w ASP.NET - przyspiesz ładowanie strony</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-aspnet-bundler.jpg&quot; alt=&quot;Pieniądze&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Transmisja w Internecie przyspiesza z dnia na dzień.  Jeszcze 15 lat temu na załadowanie prostej strony Interii z grą flash czekałem około minuty. Obecnie duże aplikacje internetowe obsługują setki tysięcy klientów w każdej sekundzie. Każde z żądań musi być obsłużone w przeciągu kilku sekund. Każde przeciążenie serwera jest potencjalną stratą dla właściciela aplikacji.&lt;/p&gt;

&lt;h2&gt;Drogi optymalizacji&lt;/h2&gt;
&lt;p&gt;Mam aplikację, która cieszy się popularnością. Obecnie nie stać mnie na skalowanie w którąkolwiek stronę, a użytkownicy zaczynają dostawać błąd HTTP 504 lub strona ładuje się potwornie długo. Co zatem mogę poprawić?&lt;/p&gt;

&lt;p&gt;Istnieją dwie drogi warte sprawdzenia, a mianowicie:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;zmniejszenie objętości komunikatów,&lt;/li&gt;
    &lt;li&gt;zmniejszenie liczby komunikatów.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do zmniejszenia objętości komunikatów mogę wykorzystać mechanizm minifikacji (kompresji skryptów i styli), a także kompresję HTTP. W celu zmniejszenia liczby żądań do mojego serwera użyję bundlera i serwerów CDN.&lt;/p&gt;

&lt;h2&gt;Bundler&lt;/h2&gt;
&lt;p&gt;Na stronie głównej aplikacji mam dołączonych kilkadziesiąt plików CSS i JavaScript. Co się dzieje podczas ładowania strony? Przeglądarka dla każdego pliku wykonuje osobne żądanie HTTP! Jeżeli klient ma włączone cachowanie, zawartość plików zostanie załadowana jedynie raz. Przy kolejnych odwiedzinach serwer będzie zwracał HTTP 304. W ten sposób powstają dwa problemy:&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;serwer jest niepotrzebnie obciążany dodatkowymi zapytaniami,&lt;/li&gt;
    &lt;li&gt;klient wykonuje zbędne zapytania, co wydłuża czas ładowania strony.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Problem można częściowo rozwiązać za pomocą bundlera. &lt;strong&gt;Bundler jest narzędziem łączącym kilka plików w jeden.&lt;/strong&gt; ASP.NET używa do tego celu biblioteki &lt;em&gt;Microsoft ASP.NET Web Optimization Framework&lt;/em&gt;. Wdrożenie “paczkowania” jest bardzo proste.&lt;/p&gt;

&lt;p&gt;Chcę połączyć zawartość styli załączonych za pomocą kodu:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/Content/bootstrap.css&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/Content/site.css&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;W pierwszym kroku wybieram pliki, które chcę scalić. Dodaję wpis do pliku App_Start\BundleConfig.cs (na końcu funkcji &lt;em&gt;RegisterBundles()&lt;/em&gt;):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;n&quot;&gt;bundles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;StyleBundle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/Content/css&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;~/Content/bootstrap.css&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;~/Content/site.css&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;W drugim kroku możemy już skorzystać z bundla. W treści mojego widoku zastępuję stary kod HTML za pomocą kodu:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;n&quot;&gt;@Styles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/Content/css&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;W wyniku tej operacji ASP.NET załącza do dokumentu jeden styl CSS, który jest sklejeniem dwóch wymienionych plików:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/Content/css?v=Bz3KZjU_pdOm2wAVr7z_ylCuQzQDs1O8N6pV4cvXc_Q1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2&gt;Minifikacja&lt;/h2&gt;
&lt;p&gt;Otwierając otrzymany plik widzę nietypową zawartość:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nt&quot;&gt;article&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;aside&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;figcaption&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;figure&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;footer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;hgroup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;nav&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;section&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;audio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(...)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Powstała paczka jest pozbawiona zbędnych białych znaków i komentarzy - jest zminifikowana. &lt;/strong&gt;Spakowanie danych w ten sposób pozwala na zmniejszenie wielkości pliku nawet o kilkadziesiąt procent.
W przypadku plików JavaScript minifikacja idzie o krok dalej. Skraca nazwy lokalnych funkcji i zmiennnych. W związku z tym plik jest jeszcze mniejszy, co oszczędza przepustowość serwera.
Zminifikowane wersje skryptów i styli zazwyczaj są dostarczane wraz z oryginalnym kodem źródłowym w paczce NuGet. Jeżeli tak nie jest, możesz użyć narzędzia do minifikacji, np. &lt;a title=&quot;Web Essentials 2013&quot; href=&quot;http://visualstudiogallery.msdn.microsoft.com/56633663-6799-41d7-9df7-0f2a504ca361&quot; target=&quot;_blank&quot;&gt;Web Essentials&lt;/a&gt;. Istotne jest, aby zminifikowany skrypt/styl miał taką samą nazwę jak oryginał, a zmieniony format na .min.js/.min.cs (np. script.js -&amp;gt; script.min.js).&lt;/p&gt;

&lt;h2&gt;Serwery CDN&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Serwery CDN &lt;/em&gt;są publicznymi repozytoriami popularnych skryptów i arkuszy stylów (np. bootstrap, jquery, angular.js). Utrzymywane są przez dużych dostawców usług internetowych, np. Google. Korzystanie z nich rozwiązuje problem ograniczenia liczby połączeń, a także ułatwia korzystanie z cache przeglądarku.&lt;/p&gt;
&lt;h3&gt;Ograniczenie liczby połączeń w przeglądarkach WWW&lt;/h3&gt;
&lt;p&gt;Przeglądarki internetowe mają domyślnie ograniczoną liczbę połączeń z danym serwerem. Jeżeli moja aplikacja będzie miała zbyt wiele zależności w osobnych plikach, nie wszystkie będą pobierane równolegle. Użycie serwera CDN zmniejszy licznik równoległych połączeń dla serwera mojej aplikacji.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;http://www.stevesouders.com/blog/2008/03/20/roundup-on-parallel-connections/&quot; target=&quot;_blank&quot;&gt;Internet Explorer 7 i kilka innych przeglądarek&lt;/a&gt; ograniczają liczbę połączeń na serwer do dwóch. W przypadku pisania aplikacji internetowej dla starszych przeglądarek użycie CDNów może dać istotne przyspieszenie ładowania strony.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Cache&lt;/h3&gt;
&lt;p&gt;Popularne skrypty/style z serwerów CDN prawdopodobnie znajdują się już w cache przeglądarki użytkownika. Zysk jest oczywisty - klient nie musi ponownie pobierać skryptu/stylu.&lt;/p&gt;

&lt;h3&gt;Popularne serwery CDN&lt;/h3&gt;
&lt;p&gt;Serwery z których korzystam to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;Bootstrap CDN&quot; href=&quot;http://www.bootstrapcdn.com/&quot; target=&quot;_blank&quot;&gt;Bootstrap CDN&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a title=&quot;Google Hosted Libraries&quot; href=&quot;https://developers.google.com/speed/libraries/devguide?hl=pl&quot; target=&quot;_blank&quot;&gt;Google Hosted Libraries&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a title=&quot;Microsoft Ajax Content Delivery Network&quot; href=&quot;http://www.asp.net/ajaxlibrary/CDN.ashx&quot; target=&quot;_blank&quot;&gt;Microsoft Ajax Content Delivery Network&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a title=&quot;CDNJS&quot; href=&quot;http://cdnjs.com/&quot;&gt;Cloudflare CDNJS&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Fallback, czyli co zrobić, gdy serwer CDN nie odpowiada&lt;/h3&gt;
&lt;p&gt;Czasem zdarza się sytuacja, w której klient nie ma połączenia z serwerem CDN. W takiej sytuacji moja strona załaduje się bez niezbędnych skryptów. Rozwiązaniem tego problemu jest tzw. &lt;em&gt;fallback&lt;/em&gt;, czyli załączenie biblioteki z mojego serwera w przypadku awarii CDN. Implementacja w HTML/JS jest niezwykle prosta:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jQuery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;script src=&quot;/path/to/your/jquery&quot;&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;');}
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Oczywiście przy takim podejściu tracimy możliwość globalnej zmiany załączonego skryptu w &lt;em&gt;BundleConfig.cs&lt;/em&gt;. Na szczęście ASP.NET wspiera fallback:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;n&quot;&gt;bundles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UseCdn&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jquery&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ScriptBundle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/bundles/jquery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;//ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.1.min.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/Scripts/jquery-{version}.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;jquery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CdnFallbackExpression&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;window.jQuery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bundles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jquery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;ASP.NET obsługuje również fallback dla arkuszy CSS, jednak rozwiązanie problemu ze stylami jest nieco trudniejsze. Więcej informacji znajdziesz &lt;a href=&quot;https://github.com/EmberConsultingGroup/StyleBundleFallback&quot;&gt;tutaj&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Bundler vs CDN&lt;/h3&gt;
&lt;p&gt;Co jest bardziej opłacalne: połączenie kilku skryptów w jeden i dołączenie do dokumentu HTML, czy załączenie każdego osobno za pośrednictwem CDNów? Jeżeli masz możliwość, użyj serwerów CDN. Bundler jest świetnym rozwiązaniem w przypadku własnych lub mało popularnych skryptów.&lt;/p&gt;

&lt;h2&gt;Kompresja HTTP (IIS)&lt;/h2&gt;
&lt;p&gt;Serwer IIS ma możliwość kompresowania treści komunikatów osobno dla plików statycznych i generowanych dynamicznie. Istnieje 10 poziomów kompresji. Każdy kolejny daje większy stopień kompresji przy jednoczesnym większym zużyciu czasu procesora. Co więcej, IIS ma możliwość wyłączenia kompresji przy dużym obciążeniu CPU. Powołując się na &lt;a href=&quot;http://weblogs.asp.net/owscott/archive/2009/02/22/iis-7-compression-good-bad-how-much.aspx&quot; target=&quot;_blank&quot;&gt;ten test&lt;/a&gt;, ustaliłbym poziom kompresji następująco:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;pliki statyczne: 7-9, w zależności od częstości używania plików (pliki statyczne są cachowane),&lt;/li&gt;
    &lt;li&gt;pliki dynamiczne 0-4, w zależności od klientów (np. klienci mobilni mają ograniczone możliwości przesyłania danych przez sieć komórkową).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Pimp my bundler&lt;/h2&gt;
&lt;p&gt;Poniżej znajdziecie ściągę dla popularnych skryptów, wraz z fallbackami:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// jQuery&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jquery&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ScriptBundle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/bundles/jquery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CdnFallbackExpression&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;window.jquery&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;jquery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/Scripts/jquery-{version}.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bundles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jquery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// jQuery UI&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jqueryUi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ScriptBundle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/bundles/jquery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CdnFallbackExpression&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;window.jquery.ui&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;jqueryUi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/Scripts/jquery-{version}.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bundles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jqueryUi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Bootstrap JS&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bootstrap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ScriptBundle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/bundles/bootstrap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CdnFallbackExpression&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;$.fn.modal&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bootstrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/Scripts/bootstrap.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bundles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bootstrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Respond.js&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;respondjs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ScriptBundle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/bundles/respondjs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CdnFallbackExpression&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;window.respond&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;respondjs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/Scripts/respond.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bundles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;respondjs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Moment.js&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;momentjs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ScriptBundle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/bundles/momentjs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;//cdnjs.cloudflare.com/ajax/libs/moment.js/2.6.0/moment.min.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CdnFallbackExpression&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;window.moment&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;momentjs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/Scripts/moment.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bundles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;momentjs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Mon, 12 May 2014 06:52:46 -0500</pubDate>
        <link>https://www.binarythoughts.pl/2014/05/bundler-w-asp-net/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2014/05/bundler-w-asp-net/</guid>
        
        <category>aspnet</category>
        
        
      </item>
    
      <item>
        <title>Automatyczny deploy na Windows Azure</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-azure-automatic-deploy.png&quot; alt=&quot;Konfigurator Microsoft Azure Websites&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Automatyzacja deployowania pozwala na skupienie się na pisaniu aplikacji. Skutecznie eliminuje martwienie się o umieszczanie kolejnych wersji oprogramowania na serwerze. Narzędzia opisane w tym poradniku pozwalają na przełączanie pomiędzy kilkoma ostatnimi wersjami naszego projektu, a także automatycznie uruchamiają automatyczne testy (np. testy jednostkowe), oczywiście jeżeli zostały dołączone do solucji. W skrócie, będziesz miał/a mniej roboty z pierdołami.&lt;/p&gt;

&lt;h2&gt;Wymagania&lt;/h2&gt;
&lt;ul&gt;
    &lt;li&gt;Visual Studio 2013,&lt;/li&gt;
    &lt;li&gt;Windows Azure SDK dla platformy .NET (&lt;a href=&quot;http://www.windowsazure.com/pl-pl/downloads/&quot;&gt;http://www.windowsazure.com/pl-pl/downloads/&lt;/a&gt;),&lt;/li&gt;
    &lt;li&gt;Konto Microsoft (dawniej Live ID).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Krok 1. Zakładamy konto na platformie Visual Studio Online&lt;/h2&gt;
&lt;p&gt;Visual Studio Online (dawniej Team Foundation Service), jest internetowym narzędziem służącym do zarządzania projektem i kontroli wersji kodu.&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Wchodzimy na stronę: &lt;a href=&quot;http://www.visualstudio.com/&quot;&gt;http://www.visualstudio.com/&lt;/a&gt;,&lt;/li&gt;
    &lt;li&gt;Logujemy się za pomocą konta Microsoft,&lt;/li&gt;
    &lt;li&gt;Przechodzimy przez kolejne kroki, podając nazwę naszego VS Online.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Krok 2. Zakładamy konto Windows Azure&lt;/h2&gt;
&lt;p&gt;Windows Azure jest publiczną chmurą Microsoftu, pozwalającą na umieszczanie naszych aplikacji bez zbędnego konfigurowania serwera. W scenariuszu, którego użyjemy, aplikacja trafi na Azure Web Sites – kontener służący do przechowywania aplikacji internetowych, np. ASP.NET.&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Wchodzimy tutaj: &lt;a href=&quot;http://www.windowsazure.com/pl-pl/pricing/free-trial/&quot;&gt;http://www.windowsazure.com/pl-pl/pricing/free-trial/&lt;/a&gt;,&lt;/li&gt;
    &lt;li&gt;Zakładamy nowego triala.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Uwaga! Do rejestracji potrzebna będzie karta płatnicza. Strony internetowe w podstawowym planie są bezpłatne (do 10 sztuk), jednak jest to wymóg, w razie podniesienia planu lub użycia innych usług. Dla pewności skorzystaj z karty prepaidowej. W wielu bankach takie karty są darmowe.&lt;/p&gt;
&lt;h2&gt;Krok 3. Dodajemy nowy projekt do VS Online&lt;/h2&gt;
&lt;ol&gt;
    &lt;li&gt;Wchodzimy do naszego VS Online: &lt;em&gt;twojaunikalnanazwa&lt;/em&gt;.visualstudio.com,&lt;/li&gt;
    &lt;li&gt;Zakładamy nowy projekt, wybierając jako system kontroli wersji Git:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-silkbazaar-vso.png&quot; alt=&quot;Przycisk dodawania nowego projektu&quot; width=&quot;200&quot; height=&quot;101&quot; /&gt;
&lt;figcaption&gt;Rysunek 1. Przycisk dodawania nowego projektu&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-vso-new.png&quot; alt=&quot;Formularz dodawania nowego projektu&quot; width=&quot;557&quot; height=&quot;472&quot; /&gt;
&lt;figcaption&gt;Rysunek 2. Formularz dodawania nowego projektu&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;ol start=&quot;3&quot;&gt;
    &lt;li&gt;Wchodzimy do naszego projektu i przechodzimy do zakładki Code,&lt;/li&gt;
    &lt;li&gt;Umieszczamy nasz kod w repozytorium zgodnie ze wskazówkami:
        &lt;ol type=&quot;a&quot;&gt;
            &lt;li&gt;Jeżeli mamy już założony projekt w środowisku Visual Studio:
                &lt;ol type=&quot;i&quot;&gt;
                    &lt;li&gt;dodajemy go do kontroli wersji,&lt;/li&gt;
                    &lt;li&gt;dodajemy połączenie ze zdalnym repozytorium i synchronizujemy kod.&lt;/li&gt;
                &lt;/ol&gt;
            &lt;/li&gt;
        &lt;/ol&gt;
    &lt;/li&gt;
&lt;/ol&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-vs-add-remote.png&quot; alt=&quot;Łączenie Visual Studio ze zdalnym projektem VS Online&quot; width=&quot;300&quot; height=&quot;258&quot; /&gt;
&lt;figcaption&gt;Rysunek 3. Łączenie Visual Studio ze zdalnym projektem VS Online&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-vs-add-remote-2.png&quot; alt=&quot;Publikowanie lokalnego repozytorium do aktualnie połączonego projektu VSO&quot; width=&quot;384&quot; height=&quot;269&quot; /&gt;
&lt;figcaption&gt;Rysunek 4. Publikowanie lokalnego repozytorium do aktualnie połączonego projektu VSO&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-vs-add-remote-3.png&quot; alt=&quot;Komunikat potwierdzający umieszczenie kodu w repozytorium VS Online&quot; width=&quot;291&quot; height=&quot;42&quot; /&gt;
&lt;figcaption&gt;Rysunek 5. Komunikat potwierdzający umieszczenie kodu w repozytorium VS Online&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;ol start=&quot;2&quot; type=&quot;a&quot;&gt;
    &lt;li&gt;Jeżeli nie mamy kodu, tworzymy nowy projekt w Visual Studio, a następnie wracamy do punktu a.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Microsoft opublikował &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/hh850445(v=vs.120).aspx#local_new_add&quot;&gt;instrukcję dot. Gita w Visual Studio&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Krok 4. Zakładamy nową stronę na Windows Azure&lt;/h2&gt;
&lt;ol&gt;
    &lt;li&gt;Wchodzimy na &lt;a href=&quot;https://manage.windowsazure.com/&quot;&gt;Windows Azure Management Portal&lt;/a&gt;,&lt;/li&gt;
    &lt;li&gt;Dodajemy nową aplikację, klikając na przycisk &lt;i&gt;New&lt;/i&gt; (lewy dolny róg okna):&lt;/li&gt;
&lt;/ol&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-azure-1.png&quot; alt=&quot;Interfejs dodawania usług Windows Azure&quot; width=&quot;720&quot; height=&quot;193&quot; /&gt;
&lt;figcaption&gt;Rysunek 6. Interfejs dodawania usług Windows Azure&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-azure-2.png&quot; alt=&quot;Dodawanie Azure Web Site, krok 1.&quot; width=&quot;720&quot; height=&quot;428&quot; /&gt;
&lt;figcaption&gt;Rysunek 7. Dodawanie Azure Web Site, krok 1.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Wkroku 1. (rysunek 7.) wybieramy nową, darmową bazę SQL. Unikniemy w ten sposób niepotrzebnych kosztów. Podajemy adres, pod którym będzie dostępna nasza aplikacja. Stronę umieszczamy w regionie &lt;i&gt;West Europe&lt;/i&gt;, gdyż jest to lokalizacja najbliższa Polsce.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-azure-3.png&quot; alt=&quot;Dodawanie Azure Web Site, krok 2.&quot; width=&quot;700&quot; height=&quot;424&quot; /&gt;
&lt;figcaption&gt;Rysunek 8. Dodawanie Azure Web Site, krok 2.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;W kroku 2. (rysunek 8.) dodajemy nowy serwer SQL. Podajemy nazwę serwera, a także nazwę i hasło użytkownika. Serwer umieszczamy również w &lt;em&gt;West Europe&lt;/em&gt;.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-azure-4.png&quot; alt=&quot;Dodawanie Azure Web Site, krok 3.&quot; width=&quot;701&quot; height=&quot;435&quot; /&gt;
&lt;figcaption&gt;Rysunek 9. Dodawanie Azure Web Site, krok 3.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;W kroku 3. (rysunek 9.) wybieramy serwer repozytoriów – Visual Studio Online.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-azure-5.png&quot; alt=&quot;Dodawanie Azure Web Site, krok 4.&quot; width=&quot;720&quot; height=&quot;405&quot; /&gt;
&lt;figcaption&gt;Rysunek 10. Dodawanie Azure Web Site, krok 4.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;W kolejnym kroku (rysunek 10.) podajemy adres naszego zbioru projektów. Następnie naciskamy przycisk &lt;i&gt;Authorize Now&lt;/i&gt;. W nowym oknie klikamy przycisk &lt;i&gt;Accept&lt;/i&gt;.&lt;/p&gt;

&lt;figure&gt;
    &lt;img src=&quot;/images/post-azure-automatic-deploy-azure-6.png&quot; alt=&quot;Dodawanie Azure Web Site, krok 5.&quot; width=&quot;720&quot; height=&quot;451&quot; /&gt;
&lt;figcaption&gt;Rysunek 11. Dodawanie Azure Web Site, krok 5.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;W kroku 5. (rysunek 11.) wybieramy repozytorium, z którego Azure ma pobierać kod źródłowy.&lt;/p&gt;

&lt;h2&gt;Automatyczny deploy na Windows Azure&lt;/h2&gt;
&lt;p&gt;Po zaakceptowaniu formularza, nasza konfiguracja dobiegła końca. Wystarczy wypchnąć następną wersję projektu na repozytorium. Windows Azure samodzielnie pobierze nasze zmiany, skompiluje kod i umieści go jako aktualnie działającą aplikację.&lt;/p&gt;
</description>
        <pubDate>Wed, 18 Dec 2013 20:51:12 -0600</pubDate>
        <link>https://www.binarythoughts.pl/2013/12/automatyczny-deploy-na-windows-azure/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2013/12/automatyczny-deploy-na-windows-azure/</guid>
        
        <category>aspnet</category>
        
        <category>visualStudio</category>
        
        <category>vsOnline</category>
        
        <category>azure</category>
        
        
      </item>
    
      <item>
        <title>Asynchroniczność w ASP.NET - wprowadzenie</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-async-aspnet-intruduction.png&quot; alt=&quot;Asynchroniczne metody w ASP.NET&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Asynchroniczność w ASP.NET to temat, który ostatnio przewija się gdzie nie spojrzę.
Microsoftowy zespół od ASP.NET kilka miesięcy temu postanowił zatruć życie początkującym programistom tej platformy.
Jak to się stało? Otóż w nowej wersji MVC usunęli &lt;a title=&quot;ASP.NET Membership Provider (MSDN, en)&quot; href=&quot;http://msdn.microsoft.com/en-us/library/yh26yfzy(v=VS.100).aspx&quot; target=&quot;_blank&quot;&gt;starą bibliotekę do zarządzania uwierzytelnianiem i autoryzacją użytkowników&lt;/a&gt;.
Co do samej zmiany nie będę się wdawał w szczegóły - jak wszystko, ma swoje dobre i złe strony.
Istotne jest to, że szablon dla nowych aplikacji ASP.NET MVC 5 jest wypchany wywołaniami metod z końcówką Async.
Większość tego postu odnosi się do wszystkich aplikacji internetowych, nie tylko ASP.NET, czy innych frameworków .NETowych.&lt;/p&gt;

&lt;h2&gt;Po co wielowątkowość w aplikacjach internetowych?&lt;/h2&gt;
&lt;p&gt;Aplikacje internetowe z natury muszą być wielowątkowe.
Wyobraźmy sobie sytuację, gdzie do naszego serwera WWW przychodzą równocześnie sto żądań HTTP.
Jeżeli nie rozdzielimy obliczeń:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;nie wykorzystujemy w pełni naszego procesora - po co 8 rdzeni na serwerze, skoro wszystkie obliczenia wykonujemy na jednym?&lt;/li&gt;
    &lt;li&gt;prosimy się o atak &lt;a title=&quot;Denial of Service (OWASP, en)&quot; href=&quot;https://www.owasp.org/index.php/Denial_of_Service&quot; target=&quot;_blank&quot;&gt;odmowy dostępu&lt;/a&gt; - nasz system operacyjny nie będzie kolejkował żądań.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oczywiście developerzy samej aplikacji nie muszą się tym zwykle przejmować.
Umieszczając aplikację na serwerze WWW (IIS, Apache etc.) mamy ten problem z głowy.
O co więc chodzi z tym wpisem? Kolejkowanie żądań czasem nie wystarczy.&lt;/p&gt;

&lt;h2&gt;Kiedy powinienem pisać asynchronicznie?&lt;/h2&gt;
&lt;p&gt;Zasadniczo, powody są trzy:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;wykonujesz operację na systemie plików (bazy danych też zwykle trzymane są na dysku),&lt;/li&gt;
    &lt;li&gt;używasz zdalnego API (np. wrzucasz zdjęcia kotów na Facebooka),&lt;/li&gt;
    &lt;li&gt;wykonujesz skomplikowane obliczenia, które można zrównoleglić.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pierwsze dwa przypadki są do siebie podobne - oddajemy obliczenia do innego urządzenia (kontroler dysku, zdalny serwis).
Co się wtedy dzieje z naszym wątkiem, w którym obsługujemy żądanie? Nasz wątek czeka. A mógłby robić inne rzeczy… :-)&lt;/p&gt;

&lt;h2&gt;Asynchroniczność to nie same zalety&lt;/h2&gt;
&lt;p&gt;Jak się możecie domyślać, wątki też kosztują. Zwykle serwery WWW mają dostępną pulę wątków, dzięki czemu nie musimy ich tworzyć i zabijać.
Kosztem jest jednak przełączanie się pomiędzy wątkami, odpowiednia synchronizacja i przekazywanie danych.&lt;/p&gt;

&lt;p&gt;Kolejna sprawa - klasyczne programowanie wielowątkowe jest trudne, musimy unikać zakleszczeń.
W kolejnych wpisach pokażę, jak .NET 4.5 pozwala uniknąć tego problemu.&lt;/p&gt;

&lt;p&gt;Na koniec zostaje perełka, a mianowicie: aplikacja musi być asynchroniczna “all the way”.
Co to znaczy? Jeżeli napiszemy asynchroniczne repozytorium (np. do zapisywania danych do BD),
to asynchroniczne musi być również wszystko, co wywołuje naszą metodę - serwis, kontroler, framework.
W kolejnych wpisach przedstawię jak wygląda obecnie ASP.NET MVC i Entity Framework pod kątem asynchroniczności,
a także jak możecie to wykorzystać.&lt;/p&gt;
</description>
        <pubDate>Thu, 12 Dec 2013 07:51:17 -0600</pubDate>
        <link>https://www.binarythoughts.pl/2013/12/asynchronicznosc-w-asp-net-wprowadzenie/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2013/12/asynchronicznosc-w-asp-net-wprowadzenie/</guid>
        
        <category>aspnet</category>
        
        <category>async</category>
        
        
      </item>
    
      <item>
        <title>Ehlo Wurld</title>
        <description>&lt;div&gt;&lt;img src=&quot;/images/post-main-image-ehlo-wurld.jpg&quot; alt=&quot;Hello World na pieczywie&quot; style=&quot;margin-bottom: 15px;&quot;&gt;&lt;/img&gt;&lt;/div&gt;&lt;p&gt;Paw paw.&lt;/p&gt;

&lt;p&gt;Rebootuję bloga. Będzie więcej. Będzie technicznie. Będzie z dystansem.
Będą łzy, trudne sprawy i przelewanie krwi. Cyfrowej, oczywiście.
Tematem będzie to, czym obecnie się zajmuję - &lt;del&gt;różowe kucyki&lt;/del&gt; informatyka.
A właściwie świeże spojrzenie na nią, moim okiem oczywiście.&lt;/p&gt;

&lt;p&gt;Zapraszam do czytania!&lt;/p&gt;

&lt;p&gt;A, będą jeszcze obrazki. Duże.&lt;/p&gt;
</description>
        <pubDate>Wed, 11 Dec 2013 18:58:56 -0600</pubDate>
        <link>https://www.binarythoughts.pl/2013/12/ehlo-wurld/</link>
        <guid isPermaLink="true">https://www.binarythoughts.pl/2013/12/ehlo-wurld/</guid>
        
        <category>devLife</category>
        
        
      </item>
    
  </channel>
</rss>
