/ 18.11.2024
Spis treści
TL;DR
Wydajność jest kluczowym aspektem tworzenia oprogramowania i może być rozumiana w kilku kontekstach, w tym wydajności algorytmicznej, wykorzystania zasobów i produktywności programistów.
ISO/IEC 25010 definiuje wydajność jako zdolność produktu do wykonywania swoich funkcji w określonym czasie i przy określonych parametrach przepustowości oraz efektywnego wykorzystania zasobów w określonych warunkach.
Spring Framework zapewnia kilka funkcji, które przyczyniają się do zwiększenia wydajności w różnych kontekstach:
- Java 21 i wątki wirtualne: Spring Boot 3.2 obsługuje wirtualne wątki Java 21, które są lżejsze i bardziej wydajne niż tradycyjne wątki.
- GraalVM: Wsparcie dla budowania natywnych obrazów, które mogą znacznie skrócić czas uruchamiania i zmniejszyć zużycie pamięci przez aplikacje Java.
- Sterowane zdarzeniami: W projektach Spring Framework można zapewnić kompleksowy wybór rozwiązań sterowanych zdarzeniami, w tym brokerów komunikatów i przetwarzania strumieniowego.
- Wzorce projektowe integracji w przedsiębiorstwie: Spring Integration upraszcza przesyłanie komunikatów w aplikacjach Spring i ułatwia integrację z systemami zewnętrznymi za pośrednictwem deklaratywnych adapterów.
- Brokerzy komunikatów wysokiego poziomu: Spring zapewnia rozbudowane narzędzia do płynnej integracji z systemami przesyłania wiadomości, takimi jak JMS, AMQP, RabbitMQ, Kafka i Pulsar.
- Przetwarzanie strumieniowe: Narzędzia Spring Frameworks, takie jak Spring Cloud Stream, upraszczają tworzenie mikrousług opartych na komunikatach, a Spring Cloud Data Flow upraszcza budowanie i wdrażanie złożonych potoków przetwarzania danych do przetwarzania strumieniowego i wsadowego w środowiskach Cloud Foundry i Kubernetes.
Java i Spring Framework są popularnymi narzędziami do tworzenia aplikacji backendowych i nadal mają się dobrze w 2024 roku. Wynika to z bogatej dokumentacji, wieloletniego doświadczenia produkcyjnego i mnóstwa narzędzi open source.
Czym jest wydajność w tworzeniu oprogramowania?
Zanim zagłębimy się w zrozumienie tego, co sprawia, że Spring Framework (nadal) jest dobrym wyborem w nowoczesnym rozwoju backendu, powinniśmy zacząć od podstawowej i teoretycznej wiedzy. Wydajność jako miara tworzonych rozwiązań jest jedną z podstawowych cech oprogramowania i systemów. Można ją rozumieć w kilku kontekstach, dlatego chciałbym podkreślić kilka najważniejszych z nich.
Wydajność algorytmiczna
Miara średniego czasu wykonania niezbędnego algorytmowi do ukończenia pracy na zestawie danych…. Jeśli dwa algorytmy dla tego samego problemu są tego samego rzędu, to są one w przybliżeniu tak samo wydajne pod względem obliczeniowym. Efektywność algorytmu jest przydatna do ilościowego określania trudności w implementacji niektórych problemów (John Daintith i Edmund Wright: A Dictionary of Computing).
Każdy programista w jakiś sposób zetknął się z tą definicją. Możemy uznać, że jest to optymalne wykorzystanie zasobów obliczeniowych, zdefiniowanych jako czas obliczeń i miejsce w pamięci. Ponieważ obie te wartości są dość trudne do porównania, dlatego też powstała dobrze znana notacja Big O. Najpierw przez dwóch niemieckich matematyków, Paula Bachmanna i Edmunda Landau’a. Ciekawostka: litera O to skrót od niemieckiego Ordnung, wyrażającego porządek aproksymacji. Było to pod koniec 1900 roku. Następnie, w 1976 roku, słynny profesor z Uniwersytetu Standford, Donald Kruth, zainspirował się istniejącą już notacją Big Omega i wprowadził ją do informatyki.
Od tego momentu większość z nas jest już zaznajomiona z daną tabelą:
Definicje te są nadal aktualne i niezwykle pomocne w ocenie złożoności problemów w branży IT.
ISO/IEC 25010
Do tej pory powiązaliśmy czas i przestrzeń jako dwie kluczowe wartości dla oceny wydajności. To jeszcze nie koniec. W tym artykule przyjrzymy się bardziej formalnej definicji zaproponowanej przez Międzynarodową Organizację Normalizacyjną, najbardziej znaną jako ISO. Ponieważ na przestrzeni wieków wprowadziła ona kilka standardów, które obejmują wydajność w jakiejś formie, dziś skoncentruję się konkretnie na jednym, który jest ściśle związany z tworzeniem oprogramowania:
ISO/IEC 25010:2011 i jej poprawiona wersja ISO/IEC 25010:2023.
Jak widać z tego kompleksowego spojrzenia, wydajność odgrywa istotną rolę, ponieważ została wyróżniona jako jedna z 8 cech oprogramowania.
Wydajność: zdolność produktu do wykonywania swoich funkcji w określonym czasie i przy określonych parametrach przepustowości oraz do efektywnego wykorzystania zasobów w określonych warunkach.
Uwaga 1: Zasobami mogą być procesor, pamięć, pamięć masowa i urządzenia sieciowe.
Uwaga2: Zasoby mogą obejmować inne produkty programowe, konfigurację oprogramowania i sprzętu systemu, energię i materiały
(Międzynarodowa Organizacja Normalizacyjna: ISO/IEC 25010:2023 – Model jakości produktu)
Otrzymaliśmy kilka dodatkowych perspektyw i zagadek na główny temat. Jak dotąd mamy zarówno matematyczne, jak i formalne, ustandaryzowane definicje. Na tym etapie myślę, że brakuje opinii z perspektywy przepływu pracy inżynierów podczas rozwiązywania problemów lub wymagań domeny.
Produktywny (wydajny?) inżynier
Zanim omówimy ten temat dalej, porównajmy szybko wydajność z produktywnością. Produktywność dotyczy tego, ile możesz osiągnąć, podczas gdy wydajność dotyczy tego, jak dobrze wykorzystujesz swoje zasoby, aby wykonać swoje zadania. Możemy to również uprościć, mówiąc, że produktywność dotyczy ilości, podczas gdy wydajność dotyczy jakości.
„Produktywność definiuje się jako ilość użytecznej pracy wykonanej w danym czasie. „Neal Ford: The Productive Programmer, 2008 r.
Możemy również nieco skomplikować sprawę i dodać dodatkowe zmienne do naszej definicji.
Źródło: Caitlin Sadowski, Thomas Zimmermann: Rethinking Productivity in Software Engineering
Aby osiągnąć najwyższą produktywność, powinniśmy generować jak największą produkcję – definiowaną jako wydajność przy najmniejszym wkładzie, co można rozumieć jako koszt i wydajność naszej pracy.
Bycie produktywnym programistą jest ważną częścią zestawu umiejętności nowoczesnego inżyniera, ponieważ pozwala inżynierom dostarczać większą wartość swoim zespołom i firmom. Gdy inżynierowie są produktywni, mogą dotrzymywać terminów, poprawiać jakość i obniżać koszty. Jest również bardziej prawdopodobne, że będą zadowoleni ze swojej pracy i mniej prawdopodobne, że się wypalą.
Niektóre z kluczowych cech produktywnego dewelopera obejmują:
- Efektywne zarządzanie czasem: Wiedza, jak planować i organizować swoją pracę, aby dotrzymać terminów i uniknąć wypalenia zawodowego.
- Silne umiejętności rozwiązywania problemów: Zdolność do szybkiego i skutecznego identyfikowania i rozwiązywania problemów.
- Dbałość o szczegóły: Umiejętność wyłapywania i naprawiania błędów, zanim spowodują one problemy.
- Zdolność do uczenia się nowych rzeczy: Bycie otwartym na naukę nowych technologii i technik, aby być na bieżąco z najnowszymi trendami.
Rozwijając te umiejętności, inżynierowie mogą stać się bardziej produktywni i wnieść większy wkład w swoje zespoły i organizacje.
Wydajność w projektach Spring
Wielowymiarowa definicja
Jak zauważyliśmy, definicja wydajności pojawia się w różnych kontekstach. Dlatego chciałbym zidentyfikować kluczowe funkcje framework’a i przypisać je do każdego wspomnianego kontekstu.
Natywny dla chmury
- Java 21 i wątki wirtualne
Tradycyjne wątki w Javie ograniczały liczbę jednoczesnych żądań, które serwer mógł obsłużyć. Java 21 oficjalnie zawiera wirtualne wątki jako część JDK, które są lżejsze i bardziej wydajne, pozwalając na tworzenie milionów wątków w stosie. Pierwotnie zostały one stworzone w ramach projektu Loom. Działają one na tych samych wątkach, które pełnią dla nich rolę nośników. Pozwala to serwerom obsługiwać znacznie większą liczbę żądań bez poświęcania wydajności.
- Aplikacje Spring MVC
Z perspektywy frameworka Spring, wątki wirtualne są lekkie i idealne dla Spring MVC, ponieważ mogą obsługiwać blokowanie I/O (I/O odnosi się do Input/Output w świecie komputerów, aby określić, w jaki sposób komunikacja odbywa się między systemami) bez ponoszenia wysokich kosztów tradycyjnych wątków. Spring MVC może automatycznie korzystać z wirtualnych wątków w kontenerach apletów, takich jak Tomcat i Jetty, bez konieczności wprowadzania jakichkolwiek zmian w kodzie. Funkcja ta jest dostępna natywnie w Spring Boot 3.2 i można ją włączyć za pomocą konfiguracji Spring opartej na pliku application.yml. Co warte podkreślenia, Spring WebFlux wciąż pozostaje aktualny dla rozwiązań typu non-blocking.
- Spring Cloud (natywny)
Rozwój natywny w chmurze podkreśla konieczność stosowania najlepszych praktyk w celu ulepszenia procesu dostarczania oprogramowania i zagwarantowania wartościowego rozwoju. Opiera się na powiązanych 12 czynnikach aplikacji, w ramach których metody rozwoju są zgodne z celami dostarczenia i działania, wykorzystując programowanie deklaratywne, monitorowanie i zarządzanie. Spring Cloud wspiera te style rozwoju, zapewniając kompleksowy zestaw funkcji, które zaspokajają potrzeby systemów rozproszonych.
Dla tych, którzy nie znają Spring Cloud – jest to zestaw narzędzi, które pomagają programistom szybko i łatwo budować systemy rozproszone. Zapewnia kilka funkcji, które są powszechnie używane w systemach rozproszonych, takich jak zarządzanie konfiguracją, wykrywanie usług, routing, połączenia między usługami, równoważenie obciążenia, przełączniki połączeń, rozproszone przesyłanie wiadomości, krótkoterminowe mikrousługi oraz testowanie kontraktów oparte na konsumentach i producentach. Spring Cloud działa dobrze w każdym rozproszonym środowisku aplikacji korporacyjnych, w tym na laptopach deweloperów, fizycznych centrach danych i platformach zarządzania, takich jak Cloud Foundry lub Kubernetes. Drugi z nich od kilku lat cieszy się dużą popularnością, ponieważ zapewnia deweloperom skalowalny, rozproszony framework, który zarządza klastrami i aplikacjami, co czyni go doskonałym wyborem dla obciążeń obejmujących wiele środowisk chmurowych. Ta elastyczność przynosi korzyści deweloperom, którzy mogą wdrażać aplikacje na różnych platformach chmurowych.
- GraalVM – zaawansowany JDK z natywną kompilacją obrazów w czasie rzeczywistym
Spring Boot 3.0 wprowadził natywne wsparcie dla GraalVM, które zastąpiło wcześniejszy projekt deweloperski Spring Native. Przyniosło to ogromne korzyści w zakresie redukcji wykorzystywanych zasobów. Aplikacje Java kompilowane z wyprzedzeniem przez GraalVM wymagają mniej pamięci i procesora do uruchomienia. Umożliwia wdrażanie lekkich kontenerów, które uruchamiają się w ciągu kilku milisekund, znacznie szybciej niż tradycyjne kontenery JVM. Skrócony czas uruchamiania i mniejsze zużycie pamięci optymalizują infrastrukturę aplikacji i zapewniają błyskawiczne osiągnięcie maksymalnej wydajności. Ponadto rozwiązanie to ściśle podąża za nowymi funkcjami Java, w tym wirtualnymi wątkami, zapewniając natychmiastowy dostęp do najnowszych rozwiązań.
Oczywiście ma też pewne wady, ponieważ podczas kompilacji z wyprzedzeniem (AOT) po prostu usuwa niepotrzebny kod. Główne kompromisy to:
- Natywna kompilacja obrazu zajmuje minuty zamiast sekund. Może to stanowić znaczący narzut w porównaniu do maszyny JVM, która może kompilować klasy Java w ciągu kilku sekund.
- Wymaga dodatkowych metadanych, aby poprawnie obsługiwać refleksję, proxy i inne dynamiczne zachowania JVM. Metadane te mogą być generowane automatycznie przez projekt Spring, ale mogą nie być kompletne dla wszystkich projektów.
- Połączenie transformacji Spring AOT i natywnego obrazu GraalVM wymaga od nas zamrożenia ścieżki klas i warunków bean w czasie kompilacji. Oznacza to, że nie można zmienić ścieżki klas ani warunków bean w czasie wykonywania. Należy to wziąć pod uwagę, ponieważ kontener Spring nie będzie w stanie odzwierciedlić wszystkich zmian w swoim kontekście.
- Przywracanie punktu kontrolnego JVM
CRaC to projekt OpenJDK, który zapewnia nowy interfejs API Java dla operacji punktu kontrolnego i przywracania w HotSpot JVM. Opiera się on na projekcie CRIU dla funkcji punktu kontrolnego/przywracania w systemie Linux. Umożliwia on wykonanie punktu kontrolnego uruchomionej maszyny JVM, w tym jej pamięci i stanu, na dysku i przywrócenie jej później, potencjalnie na innej maszynie. Może to być przydatne do zapisywania i przywracania stanu aplikacji oraz poprawy wydajności zimnego startu.
Projekt CRaC jest wciąż w fazie rozwoju, ale został już przyjęty przez AWS Lambda i IBM OpenLiberty. Jest to obiecująca technologia, która może sprawić, że aplikacje JVM będą bardziej wydajne i odporne.
- Sterowane zdarzeniami
Systemy sterowane zdarzeniami są zgodne z nieustannie ewoluującym krajobrazem nowoczesnych firm, w których nieustannie zachodzą liczne drobne modyfikacje. Zdolność Spring do obsługi i wykorzystywania zdarzeń umożliwia programistom tworzenie aplikacji, które odzwierciedlają tę dynamiczną naturę, utrzymując aplikacje w synchronizacji z operacjami biznesowymi. Framework Spring obejmuje kompleksowy wybór rozwiązań opartych na zdarzeniach, obejmujących integrację, przesyłanie strumieniowe, funkcje chmury i funkcje przepływu danych.
Wzorce integracji w aplikacjach korporacyjnych
Dzięki dedykowanemu projektowi Spring Integration, Spring umożliwia korzystanie z popularnych i ugruntowanych wzorców opartych na wzorcach projektowych dla przedsiębiorstw. Upraszcza on przesyłanie komunikatów w aplikacjach internetowych i ułatwia integrację z systemami zewnętrznymi za pośrednictwem deklaratywnych adapterów, które usprawniają istniejące wsparcie Spring dla zdalnego przesyłania komunikatów i planowania. Jego celem jest zapewnienie prostego podejścia do budowania rozwiązań integracyjnych dla przedsiębiorstw przy jednoczesnym zachowaniu separacji zagadnień, odwrócenia kontroli i wstrzykiwania zależności, które są podstawowymi koncepcjami tworzenia łatwego w utrzymaniu, testowalnego kodu, a także unikania silnego sprzężenia.
Poza łączeniem ze sobą szczegółowych komponentów, platforma zapewnia także kompleksowy zbiór adapterów kanałów i bram do komunikacji z systemami zewnętrznymi. Adaptery kanałów obsługują integrację jednokierunkową (wysyłanie lub odbieranie), podczas gdy bramki ułatwiają interakcje typu żądanie/odpowiedź (zarówno przychodzące, jak i wychodzące).
- Brokery komunikatów typu high-level
Nowoczesne architektury oprogramowania opierają się na systemach rozproszonych, w których brokery komunikatów mają kluczowe znaczenie dla ułatwienia komunikacji między różnymi usługami. Java Message Service, RabbitMQ, Kafka i ActiveMQ to powszechnie stosowane brokery komunikatów, z których każdy oferuje różne funkcje dostosowane do konkretnych zastosowań.
Spring Framework zapewnia rozbudowane narzędzia do płynnej integracji z systemami przesyłania wiadomości, od uproszczonej interakcji JMS API z JmsTemplate po kompleksową strukturę do obsługi asynchronicznej wymiany wiadomości. Spring AMQP oferuje podobny zestaw funkcji dostosowany do obsługi wiadomości opartych na AMQP. Dodatkowo upraszcza łączność, zapewniając opcje automatycznej konfiguracji dla RabbitTemplate i RabbitMQ. Spring WebSocket płynnie integruje się z komunikacją STOMP, a Spring rozszerza tę obsługę o startery i minimalną autokonfigurację. Dodatkowo obsługuje integrację Apache Kafka i Apache Pulsar.
- Przetwarzanie strumieniowe
Spring Cloud Stream upraszcza tworzenie mikrousług opartych na komunikatach, opierając się na Spring Boot w celu generowania samodzielnych aplikacji Spring klasy produkcyjnej. Płynnie integruje się ze Spring Integration w celu nawiązywania połączeń z brokerami komunikatów, zapewniając opcje konfiguracji niezależne od dostawcy, jednocześnie wprowadzając koncepcje trwałej semantyki publikowania-subskrypcji, grup konsumentów i partycji.
Podstawowymi elementami składowymi Spring Cloud Stream są:
- Destination Binders: Łączniki odpowiedzialne za nawiązywanie komunikacji z zewnętrznymi systemami przesyłania wiadomości.
- Destination Bindings: Pośrednicy, którzy łączą zewnętrzne systemy przesyłania wiadomości z opracowanym kodem aplikacji, zarówno producentami, jak i konsumentami,
- Messenger: Standardowy format danych wykorzystywany przez producentów i konsumentów do interakcji z Destination Binders, umożliwiający komunikację z innymi aplikacjami za pośrednictwem zewnętrznych systemów przesyłania wiadomości.
Do tego dochodzi Spring Cloud Data Flow, który upraszcza budowanie i wdrażanie złożonych potoków przetwarzania danych do przetwarzania strumieniowego i wsadowego w środowiskach Cloud Foundry i Kubernetes. Zapewnia on zestaw narzędzi do tworzenia potoków danych przy użyciu aplikacji Spring Boot, wykorzystujących wspomniane już frameworki mikrousług Spring Cloud Stream i Spring Cloud Task. Przypadki użycia przetwarzania danych obsługiwane przez Spring Cloud Data Flow obejmują ETL, import/eksport, strumieniowanie zdarzeń i analitykę predykcyjną.
Przyszłość Javy w 2024 roku
Zaczynamy rok 2024 i na chwilę obecną nie zanosi się na to, by Java traciła na znaczeniu. To wciąż niezwykle popularny język programowania. W ankiecie przeprowadzonej przez JetBrains pod koniec 2023 roku o nazwie The State of Developer Ecosystem wśród 26348 programistów na całym świecie, 49% z nich stwierdziło, że korzystało z Javy w ciągu ostatnich 12 miesięcy. Dla porównania, najpopularniejszy JavaScript był używany przez 61%. Co więcej, aż 33% deklaruje, że jest to podstawowy język, z którego korzystają, co jest najwyższym odsetkiem w tym badaniu. Nie zapominajmy, że do rodziny JVM należą również między innymi Kotlin i Scala, które cieszą się sporą popularnością. Ten pierwszy jest bardziej istotny w naszym kontekście, gdyż od 2017 roku może być wykorzystywany we frameworku Spring od wersji 5.0.
Spring Boot pozostaje popularny
Jeśli chodzi o główny framework dzisiejszego artykułu – Spring Boot według ankiety na stackoverflow.com cieszy się poparciem prawie 14% ankietowanych specjalistów, co czyni go szóstym najpopularniejszym frameworkiem backendowym i pierwszym opartym na JVM.
Ponadto, w oparciu o publiczne repozytoria utworzone na github.com, liczba utworzonych projektów w 2023 r. wyniesie ponad 106 000. Dla porównania, w node.js (który zajął najwyższe miejsce w ankiecie wspomnianej na stackoverflow.com) jest to ponad 107 000.
Java i Spring Framework to wciąż bardzo popularne narzędzia w świecie aplikacji korporacyjnych. Wpływ na to ma bogata dokumentacja, lata doświadczeń produkcyjnych oraz wiele narzędzi open-source. Spring Boot jest wciąż aktywnie rozwijany i zachowując opiniotwórczy status, znacznie łatwiej jest podążać za zalecanymi wzorcami projektowymi i architektonicznymi.
Społeczność Java
Liczba utworzonych projektów w 2023 roku wyniesie ponad 106 000. Dla porównania, w Node.js (który zajął najwyższe miejsce w ankiecie wspomnianej na stackoverflow.com) jest to ponad 107 000.
Java i Spring Framework to wciąż bardzo popularne narzędzia w świecie aplikacji korporacyjnych. Wpływ na to ma bogata dokumentacja, lata doświadczeń produkcyjnych oraz wiele narzędzi open-source. Spring Boot jest wciąż aktywnie rozwijany i zachowując opiniotwórczy status, znacznie łatwiej jest podążać za zalecanymi wzorcami projektowymi i architektonicznymi.
Podsumowanie
Wydajność jest kluczowym pojęciem w tworzeniu oprogramowania, obejmującym różne aspekty, takie jak wydajność algorytmów, wykorzystanie zasobów i produktywność programistów. Norma ISO/IEC 25010 definiuje wydajność jako zdolność produktu do wykonywania swoich funkcji w określonym czasie i przy określonych parametrach przepustowości, przy jednoczesnej optymalizacji zużycia zasobów.
Wydajność jest osiągana dzięki wirtualnym wątkom Java 21, lżejszym alternatywom dla tradycyjnych wątków, które zmniejszają narzut na wykonanie. Co więcej, natywne obrazy GraalVM umożliwiają szybsze uruchamianie aplikacji i zmniejszają ilość zajmowanej pamięci.
Rozwój oparty na zdarzeniach jest ułatwiony dzięki kompleksowemu ekosystemowi Spring, w tym Spring Integration, brokerom komunikatów i możliwościom przetwarzania strumieniowego. Upraszcza on przesyłanie komunikatów w aplikacjach i ułatwia integrację z systemami zewnętrznymi za pośrednictwem deklaratywnych adapterów. Obsługiwana jest szeroka gama brokerów komunikatów, w tym JMS, AMQP, RabbitMQ, Kafka i Pulsar. Spring Cloud Stream upraszcza tworzenie mikrousług opartych na komunikatach, a Spring Cloud Data Flow usprawnia złożone potoki przetwarzania danych do przetwarzania strumieniowego i wsadowego w środowiskach Cloud Foundry i Kubernetes.
Nieprzemijająca popularność Javy jest widoczna w jej ciągłej adopcji wśród deweloperów, o czym świadczą ankiety i repozytoria projektów. Popularność Spring Boot jest również znacząca, zajmując szóste miejsce wśród frameworków backendowych i pierwsze wśród frameworków opartych na JVM. Jego bogata dokumentacja, duże doświadczenie produkcyjne i mnogość frameworków internetowych typu open source przyczyniają się do jego trwałej atrakcyjności.
Podsumowując, Spring Boot i Java oferują kompleksowy zestaw funkcji, które zwiększają wydajność w różnych wymiarach tworzenia oprogramowania. Od algorytmicznej optymalizacji wydajności po architektury sterowane zdarzeniami i wzorce integracji korporacyjnej, Spring Boot stanowi solidną podstawę do tworzenia nowoczesnych, skalowalnych i wydajnych aplikacji Java. Ciągłe znaczenie Javy i popularność Spring Boot podkreślają zalety tych technologii we współczesnym krajobrazie tworzenia oprogramowania.
Mam nadzieję, że spodobał Ci się ten krótki przegląd wydajności w tworzeniu oprogramowania oraz funkcji, które Spring Boot i Java oferują w celu zwiększenia wydajności. Dziękuję za przeczytanie! Wkrótce pojawi się więcej treści związanych z Javą i Spring World.
Bezpiecznego i udanego kodowania.
Źródła
- Łukasz Bielarczyk: Znaczenie i interpretacja efektywności w normach ISO; 2022
- Maddy Osman: Produktywność vs. Efektywność: Jak poprawić jedno i drugie w pracy,2023
- Neal Ford: Produktywny programista, 2008
- Caitlin Sadowski, Thomas Zimmermann: Rethinking Productivity in Software Engineering, 2019 r.