Читать книгу Programowanie funkcyjne w języku C#. Jak pisać lepszy kod - Enrico Buonanno - Страница 7

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Epilog: co dalej?

Przypisy

Programowanie funkcyjne w języku C#. Jak pisać lepszy kod

Подняться наверх