Programowanie funkcyjne w języku C#. Jak pisać lepszy kod - Helion
Tłumaczenie: Witold Sikorski, Małgorzata Dąbkowska-Kowalik
ISBN: 978-83-012-0846-2
stron: 450, Format: ebook
Data wydania: 2020-11-17
Księgarnia: Helion
Cena książki: 71,20 zł (poprzednio: 87,90 zł)
Oszczędzasz: 19% (-16,70 zł)
Programowanie funkcyjne zmienia sposób myślenia o kodzie! W przypadku developerów C# techniki programowania funkcyjnego mogą znacznie poprawić zarządzanie stanem, współbieżność, obsługę wyjątków i długoterminowe utrzymywanie kodu. C# oferuje także elastyczność, która pozwala w pełni korzystać z zastosowania technik funkcyjnych. Ta książka daje niesamowitą moc nowej perspektywy. Programowanie funkcyjne w języku C# uczy, jak stosować funkcyjne podejście do rzeczywistych problemów, korzystając z języka C#. Na początku nauczysz się podstaw programowania funkcyjnego i własności języka, które pozwalają programować w sposób funkcyjny. Poprzez analizę wielu praktycznych przykładów, poznasz siłę składania funkcji, programowania przepływu danych, niemutowalnych struktur danych oraz składania monadycznego za pomocą LINQ. Książka omawia następujące tematy: pisanie czytelnego, przyjaznego dla zespołu kodu, opanowanie strumieni asynchronicznych i strumieni danych, zdecydowana poprawa obsługi błędów, event sourcing i inne wzorce programowania funkcyjnego. Lektura dla zaawansowanych programistów C# bez wcześniejszego doświadczenia w programowaniu funkcyjnym.
Osoby które kupowały "Programowanie funkcyjne w języku C#. Jak pisać lepszy kod", wybierały także:
- C# 9.0 w pigułce 173,87 zł, (53,90 zł -69%)
- Gray Hat C#. Język C# w kontroli i łamaniu zabezpieczeń 57,74 zł, (17,90 zł -69%)
- ASP.NET Core 6. Kurs video. Rozwijaj aplikacje webowe z Entity Framework Core 179,00 zł, (71,60 zł -60%)
- Platforma Xamarin. Kurs video. Poziom drugi. Zaawansowane techniki tworzenia aplikacji cross-platform 99,00 zł, (39,60 zł -60%)
- Testowanie automatyczne w .NET. Kurs video. Zastosowania frameworka nUnit 169,00 zł, (76,05 zł -55%)
Spis treści
Programowanie funkcyjne w języku C#. Jak pisać lepszy kod eBook -- spis treści
- Okładka
- Strona tytułowa
- Strona redakcyjna
- Spis treści
- Wprowadzenie
- Podziękowania
- O książce
- Część I Podstawowe pojęcia
- 1. Wprowadzenie do programowania funkcyjnego
- 1.1 Czym jest to, co nazywamy programowaniem funkcyjnym?
- 1.1.1 Funkcje jako elementy pierwszoklasowe
- 1.1.2 Unikanie zmiany stanu
- 1.1.3 Pisanie programów o silnych gwarancjach
- 1.2 W jakim stopniu język C# jest funkcyjny?
- 1.2.1 Funkcyjna natura LINQ
- 1.2.2 Elementy funkcyjne w C# 6 i C# 7
- 1.2.3 Bardziej funkcyjna przyszłość dla języka C#?
- 1.3 Myślenie w kategoriach funkcji
- 1.3.1 Funkcje jako odwzorowania
- 1.3.2 Reprezentacja funkcji w C#
- 1.4 Funkcje wyższego rzędu
- 1.4.1 Funkcje zależne od innych funkcji
- 1.4.2 Funkcje adapterowe
- 1.4.3 Funkcje, które tworzą inne funkcje
- 1.5 Używanie funkcji HOF do unikania duplikacji
- 1.5.1 Enkapsulacja przygotowania i zwolnienia w HOF
- 1.5.2 Włączanie instrukcji using do HOF
- 1.5.3 Kompromisy HOF
- 1.6 Korzyści wynikające z programowania funkcyjnego
- Ćwiczenia
- Podsumowanie
- 1.1 Czym jest to, co nazywamy programowaniem funkcyjnym?
- 2. Dlaczego czystość funkcji ma znaczenie
- 2.1 Czym jest czystość funkcji?
- 2.1.1 Czystość i efekty uboczne
- 2.1.2 Strategie zarządzania efektami ubocznymi
- 2.2 Czystość i współbieżność
- 2.2.1 Czyste funkcje są dobre do równoległego przetwarzania
- 2.2.2 Równoległe wykonywanie funkcji nieczystych
- 2.2.3 Unikanie zmiany stanu
- 2.3 Czystość i testowalność
- 2.3.1 W praktyce: scenariusz walidacji
- 2.3.2 Testowanie funkcji nieczystych
- 2.3.3 Dlaczego testowanie nieczystych funkcji jest trudne
- 2.3.4 Parametryzowane testy jednostkowe
- 2.3.5 Unikanie interfejsów nagłówkowych
- 2.4 Czystość a ewolucja obliczeń
- Ćwiczenia
- Podsumowanie
- 2.1 Czym jest czystość funkcji?
- 3. Projektowanie sygnatur funkcji i typów
- 3.1 Projektowanie sygnatury funkcji
- 3.1.1 Notacja strzałkowa
- 3.1.2 Ile informacji niesie sygnatura?
- 3.2 Przechwytywanie danych za pomocą obiektów danych
- 3.2.1 Typy podstawowe często nie są dostatecznie konkretne
- 3.2.2 Ograniczenie wejść za pomocą typów niestandardowych
- 3.2.3 Pisanie uczciwych funkcji
- 3.2.4 Łączenie wartości za pomocą krotek i obiektów
- 3.3 Modelowanie braku danych za pomocą Unit
- 3.3.1 Dlaczego void nie jest idealny
- 3.3.2 Usuwanie luki między Action a Func za pomocą Unit
- 3.4 Modelowanie możliwego braku danych za pomocą Option
- 3.4.1 Kiepskie API, których używamy na co dzień
- 3.4.2 Wprowadzenie do typu Option
- 3.4.3 Implementacja Option
- 3.4.4 Większa niezawodność dzięki zastosowaniu Option zamiast null
- 3.4.5 Option jako naturalny typ wyniku funkcji częściowych
- Ćwiczenia
- Podsumowanie
- 3.1 Projektowanie sygnatury funkcji
- 4. Wzorce w programowaniu funkcyjnym
- 4.1 Stosowanie funkcji do wewnętrznych wartości struktury
- 4.1.1 Odwzorowanie funkcji na elementach ciągu
- 4.1.2 Odwzorowanie funkcji na Option
- 4.1.3 Jak Option zwiększa poziom abstrakcji
- 4.1.4 Wprowadzenie do funktorów
- 4.2 Wykonywanie efektów ubocznych za pomocą ForEach
- 4.3 Łączenie funkcji za pomocą Bind
- 4.3.1 Połączenie ze sobą funkcji zwracających Option
- 4.3.2 Spłaszczanie zagnieżdżonych list za pomocą Bind
- 4.3.3 To nazywamy monadą!
- 4.3.4 Funkcja Return
- 4.3.5 Relacje między funktorami a monadami
- 4.4 Filtrowanie wartości za pomocą Where
- 4.5 Połączenie Option i IEnumerable za pomocą Bind
- 4.6 Kodowanie na różnych poziomach abstrakcji
- 4.6.1 Wartości regularne a podniesione
- 4.6.2 Przekraczanie poziomów abstrakcji
- 4.6.3 Map kontra Bind ponownie
- 4.6.4 Praca na właściwym poziomie abstrakcji
- Ćwiczenia
- Podsumowanie
- 4.1 Stosowanie funkcji do wewnętrznych wartości struktury
- 5. Projektowanie programów za pomocą składania funkcji
- 5.1 Złożenie funkcji
- 5.1.1 Przegląd informacji o złożeniu funkcji
- 5.1.2 Łańcuch metod
- 5.1.3 Złożenie w świecie podwyższonego poziomu
- 5.2 Myślenie w kategoriach przepływu danych
- 5.2.1 Używanie składalnego API z LINQ
- 5.2.2 Pisanie funkcji, które łatwo podlegają złożeniu
- 5.3 Programowanie przepływów pracy
- 5.3.1 Prosty przepływ pracy w celu weryfikacji
- 5.3.2 Refaktoryzacja z uwględnieniem przepływu danych
- 5.3.3 Złożenie prowadzi do większej elastyczności
- 5.4 Wprowadzenie do funkcyjnego modelowania dziedziny
- 5.5 Kompleksowy przepływ pracy po stronie serwera
- 5.5.1 Wyrażenia kontra instrukcje
- 5.5.2 Deklaratywnie kontra imperatywnie
- 5.5.3 Funkcyjne spojrzenie na warstwy
- Ćwiczenia
- Podsumowanie
- 5.1 Złożenie funkcji
- 1. Wprowadzenie do programowania funkcyjnego
- Część II W stronę funkcyjności
- 6. Funkcyjne obsługiwanie błędów
- 6.1 Bezpieczniejszy sposób przedstawiania wyników
- 6.1.1 Uchwycenie szczegółów dotyczących błędów za pomocą Either
- 6.1.2 Podstawowe funkcje do wykorzystania z Either
- 6.1.3 Porównanie Option i Either
- 6.2 Łączenie działań, które mogą się nie udać
- 6.3 Walidacja: doskonały przypadek zastosowania Either
- 6.3.1 Wybór odpowiedniej reprezentacji dla błędów
- 6.3.2 Definiowanie API opartego na Either
- 6.3.3 Dodawanie kodu walidacji
- 6.4 Przedstawianie wyników aplikacjom klienckim
- 6.4.1 Udostępnianie interfejsu typu Option
- 6.4.2 Udostępnianie interfejsu typu Either
- 6.4.3 Zwracanie wynikowego obiektu (DTO)
- 6.5 Wariacje na temat Either
- 6.5.1 Zmiana reprezentacji błędów
- 6.5.2 Specjalizowane wersje Either
- 6.5.3 Refaktoryzacja do Validation i Exceptional
- 6.5.4 Odejście od wyjątków?
- Ćwiczenia
- Podsumowanie
- 6.1 Bezpieczniejszy sposób przedstawiania wyników
- 7. Budowanie aplikacji za pomocą funkcji
- 7.1 Aplikacja częściowa: dostarczanie fragmentów argumentów
- 7.1.1 Ręczne włączanie częściowej aplikacji
- 7.1.2 Uogólnianie aplikacji częściowej
- 7.1.3 Kolejność argumentów ma znaczenie
- 7.2 Pokonywanie kaprysów rozwiązywania metod
- 7.3 Funkcje rozwinięte: zoptymalizowane pod kątem częściowej aplikacji
- 7.4 Tworzenie API przyjaznego dla aplikacji częściowej
- 7.4.1 Typy jako dokumentacja
- 7.4.2 Wyszczególnianie funkcji dostępu do danych
- 7.5 Modularyzacja i budowanie aplikacji
- 7.5.1 Modułowość w programowaniu obiektowym
- 7.5.2 Modułowość w FP
- 7.5.3 Porównanie dwóch podejść
- 7.5.4 Budowanie aplikacji
- 7.6 Redukowanie listy do jednej wartości
- 7.6.1 Metoda Aggregate w LINQ
- 7.6.2 Agregowanie wyników walidacji
- 7.6.3 Zbieranie błędów walidacji
- Ćwiczenia
- Podsumowanie
- 7.1 Aplikacja częściowa: dostarczanie fragmentów argumentów
- 8. Efektywne wykorzystywanie funkcji wieloargumentowych
- 8.1 Aplikacja funkcji w świecie podniesionych typów
- 8.1.1 Zrozumienie aplikatyw
- 8.1.2 Podnoszenie poziomu funkcji
- 8.1.3 Wprowadzenie do testowania opartego na własnościach
- 8.2 Funktory, aplikatywy, monady
- 8.3 Prawa monad
- 8.3.1 Prawa tożsamość
- 8.3.2 Lewa tożsamość
- 8.3.3 Łączność
- 8.3.4 Używanie Bind z funkcjami wieloargumentowymi
- 8.4 Poprawianie czytelności przez użycie LINQ z dowolną monadą
- 8.4.1 Korzystanie z LINQ z arbitralnymi funktorami
- 8.4.2 Używanie LINQ z dowolnymi monadami
- 8.4.3 let, where i inne klauzule LINQ
- 8.5 Kiedy używać Bind, a kiedy Apply
- 8.5.1 Walidacja za pomocą inteligentnych konstruktorów
- 8.5.2 Zbieranie błędów za pomocą przepływu aplikatywnego
- 8.5.3 Szybka porażka przy przepływie monadycznym
- Ćwiczenia
- Podsumowanie
- 8.1 Aplikacja funkcji w świecie podniesionych typów
- 9. Rozważania o funkcyjności danych
- 9.1 Pułapki mutacji stanu
- 9.2 Zrozumienie stanu, tożsamości i zmiany
- 9.2.1 Niektóre rzeczy nigdy się nie zmieniają
- 9.2.2 Reprezentowanie zmian bez mutacji
- 9.3 Wymuszanie niemutowalności
- 9.3.1 Całkowita niemutowalność
- 9.3.2 Metody kopiowania bez szablonowego kodu?
- 9.3.3 Wykorzystywanie F# do typów danych
- 9.3.4 Porównywanie strategii dla niemutowalności: konkurs brzydoty
- 9.4 Krótkie wprowadzenie do funkcyjnych struktur danych
- 9.4.1 Klasyczna lista wiązana w stylu funkcyjnym
- 9.4.2 Drzewa binarne
- Ćwiczenia
- Podsumowanie
- 10. Event sourcing: funkcyjne podejście do zapisu
- 10.1 Funkcyjne rozważania o przechowywaniu danych
- 10.1.1 Dlaczego przechowywanie danych powinno polegać wyłącznie na ich dołączaniu
- 10.1.2 Zrelaksujmy się i zapomnijmy o przechowywaniu stanu
- 10.2 Podstawy event sourcingu
- 10.2.1 Reprezentacja zdarzeń
- 10.2.2 Przechowywanie zdarzeń
- 10.2.3 Reprezentacja stanu
- 10.2.4 Przerwa na dopasowywanie do wzorca
- 10.2.5 Reprezentacja zmian stanu
- 10.2.6 Odtwarzanie bieżącego stanu na podstawie przeszłych zdarzeń
- 10.3 Architektura systemu opartego na zdarzeniach
- 10.3.1 Obsługa poleceń
- 10.3.2 Obsługa zdarzeń
- 10.3.3 Dodanie walidacji
- 10.3.4 Tworzenie widoków danych na podstawie zdarzeń
- 10.4 Porównanie różnych podejść do niemutowalnego magazynu
- 10.4.1 Datomic kontra Event Store
- 10.4.2 Jak bardzo nasza dziedzina jest sterowana zdarzeniami?
- Podsumowanie
- 10.1 Funkcyjne rozważania o przechowywaniu danych
- 6. Funkcyjne obsługiwanie błędów
- Część III Zaawansowane techniki
- 11. Leniwe wartościowanie, kontynuacje oraz piękno kompozycji monadycznej
- 11.1 Zalety leniwego wartościowania
- 11.1.1 Leniwe API działające z Option
- 11.1.2 Złożenie leniwych wartościowań
- 11.2 Obsługa wyjątków za pomocą Try
- 11.2.1 Reprezentowanie obliczeń, które mogą się nie powieść
- 11.2.2 Bezpieczne pobieranie informacji z obiektu JSON
- 11.2.3 Złożenia obliczeń, które mogą się nie udać
- 11.2.4 Złożenie monadyczne: co to znaczy?
- 11.3 Tworzenie potoku oprogramowania pośredniczącego na potrzeby dostępu do bazy danych
- 11.3.1 Złożenie funkcji, które inicjalizują/czyszczą
- 11.3.2 Przepis na uniknięcie piramidy potępienia
- 11.3.3 Przechwycenie istoty oprogramowania pośredniczącego
- 11.3.4 Implementacja wzorca zapytania dla oprogramowania pośredniczącego
- 11.3.5 Dodawanie oprogramowania pośredniczącego, które mierzy czas działania
- 11.3.6 Dodawanie oprogramowania pośredniczącego zarządzającego transakcją
- Podsumowanie
- 11.1 Zalety leniwego wartościowania
- 12. Stanowe programy i obliczenia
- 12.1 Programy, które zarządzają stanem
- 12.1.1 Utrzymywanie pamięci podręcznej uzyskanych zasobów
- 12.1.2 Refaktoryzacja w celu umożliwienia testowania i obsługi błędów
- 12.1.3 Obliczenia stanowe
- 12.2 Język do generowania danych losowych
- 12.2.1 Generowanie całkowitych liczb losowych
- 12.2.2 Generowanie innych wartości podstawowych
- 12.2.3 Generowanie bardziej złożonych struktur
- 12.3 Ogólny wzorzec obliczeń stanowych
- Podsumowanie
- 12.1 Programy, które zarządzają stanem
- 13. Posługiwanie się obliczeniami asynchronicznymi
- 13.1 Obliczenia asynchroniczne
- 13.1.1 Potrzeba działania asynchronicznego
- 13.1.2 Reprezentowanie działań asynchronicznych za pomocą Task
- 13.1.3 Zadanie jako kontener na przyszłą wartość
- 13.1.4 Obsługa błędów
- 13.1.5 API HTTP API dla konwersji walut
- 13.1.6 W razie niepowodzenia próbujmy kilka razy
- 13.1.7 Równoległe uruchamianie działań asynchronicznych
- 13.2 Funkcje przesuwne: praca z listami podniesionych wartości
- 13.2.1 Weryfikacja listy wartości za pomocą monadycznej funkcji Traverse
- 13.2.2 Zbieranie błędów walidacji za pomocą aplikatywnej funkcji Traverse
- 13.2.3 Zastosowanie wielu walidatorów do jednej wartości
- 13.2.4 Stosowanie Traverse z Task, jeśli możliwych jest wiele wyników
- 13.2.5 Definiowanie Traverse dla struktur o pojedynczej wartości
- 13.3 Łączenie asynchroniczności i walidacji (lub dowolnych innych efektów monadycznych)
- 13.3.1 Problem złożenia monad
- 13.3.2 Zmniejszenie liczby efektów
- 13.3.3 Wyrażenia LINQ ze złożeniem monad
- Podsumowanie
- 13.1 Obliczenia asynchroniczne
- 14. Strumienie danych i Reactive Extensions
- 14.1 Reprezentowanie strumieni danych za pomocą IObservable
- 14.1.1 Ciąg wartości w czasie
- 14.1.2 Subskrypcja IObservable
- 14.2 Tworzenie IObservables
- 14.2.1 Tworzenie zegara
- 14.2.2 Używanie Subject, aby poinformować IObservable, kiedy ma wysyłać sygnał
- 14.2.3 Tworzenie IObservables na podstawie subskrypcji opartych na wywołaniach zwrotnych
- 14.2.4 Tworzenie IObservables z prostszych struktur
- 14.3 Przekształcanie i łączenie strumieni danych
- 14.3.1 Przekształcenia strumienia
- 14.3.2 Łączenie i podział strumieni
- 14.3.3 Obsługa błędów w IObservable
- 14.3.4 Składamy wszystko razem
- 14.4 Implementacja kodu, który łączy wiele zdarzeń
- 14.4.1 Wykrywanie ciągów naciśnięć klawiszy
- 14.4.2 Reagowanie na wiele źródeł zdarzeń
- 14.4.3 Powiadamianie, kiedy na koncie pojawia się debet
- 14.5 Kiedy należy stosować IObservable?
- Podsumowanie
- 14.1 Reprezentowanie strumieni danych za pomocą IObservable
- 15. Wprowadzenie do współbieżności z przesyłaniem komunikatów
- 15.1 Zapotrzebowanie na współdzielony stan mutowalny
- 15.2 Zrozumienie współbieżności z przesyłaniem komunikatów
- 15.2.1 Implementowanie agentów w C#
- 15.2.2 Pierwsze kroki z agentami
- 15.2.3 Użycie agentów do obsługi równoczesnych żądań
- 15.2.4 Agenty kontra aktory
- 15.3 Funkcyjne API, implementacje oparte na agentach
- 15.3.1 Agenty jako szczegóły implementacji
- 15.3.2 Ukrywanie agentów za tradycyjnym API
- 15.4 Współbieżność z przesyłaniem komunikatów w aplikacjach LOB
- 15.4.1 Korzystanie z agenta do synchronizacji dostępu do danych konta
- 15.4.2 Przechowywanie rejestru kont
- 15.4.3 Agent nie jest obiektem
- 15.4.4 Łączenie wszystkiego ze sobą
- Podsumowanie
- 11. Leniwe wartościowanie, kontynuacje oraz piękno kompozycji monadycznej
- Epilog: co dalej?
- Przypisy