Při správě a vývoji softwarových projektů je klíčové mít jasně stanovené normy a pravidla pro řízení jednotlivých fází vývoje, od začátku až po dokončení. Mezi základní principy patří definice připravenosti (Definition of Ready) a definice dokončení (Definition of Done), které určují, kdy je úkol připraven k zahájení práce a kdy je považován za hotový. Stanovení těchto kritérií je nezbytné pro efektivní fungování týmu a úspěšné dokončení projektu.

Definice připravenosti stanovuje kritéria, která určují, kdy je položka v backlogu dostatečně vypracována, aby na ní mohl tým začít pracovat. Naopak definice dokončení specifikuje, kdy je položka považována za zcela hotovou. Tyto definice by měly být součástí týmových norem, protože stanovují jasné hranice, které usnadňují komunikaci mezi jednotlivými členy týmu a zaručují kvalitu výsledku.

Pokud jde o správu úkolů v rámci softwarového vývoje, nástroje jako GitHub nabízejí efektivní způsob, jak sledovat průběh vývoje prostřednictvím kanbanových tabulí, které automaticky přidávají problémy (issues) a pull requesty do projektu. Pro efektivní práci s těmito nástroji je klíčové správně nastavit pracovní postupy (workflows), které usnadní automatizaci procesů a zajištění plynulého toku práce. GitHub projekty také umožňují integraci s vývojovými workflow, což zjednodušuje sledování pokroku, čímž se usnadňuje spolupráce mezi členy týmu a dalšími zúčastněnými stranami.

Je také nutné zaměřit se na správné sestavení a priorizaci backlogu, který bude sloužit jako mapa pro implementaci funkcionalit aplikace. Backlog by měl být pravidelně procházen a aktualizován, přičemž je třeba se vyvarovat vytváření čistě technických úkolů, které nejsou pro uživatele relevantní. Místo toho by měly být technické problémy řešeny v kontextu funkcionality, kterou mají vyřešit. Takto strukturovaný backlog poskytuje jasný přehled o tom, co je třeba udělat, a umožňuje týmu efektivně se zaměřit na úkoly s nejvyšší prioritou.

Kromě toho je zásadní vědět, jak správně stanovit a sledovat milníky (milestones) v rámci projektu. Tyto milníky mohou sloužit jako orientační body pro tým, kdy je třeba dokončit určité části projektu, a pomáhají sledovat progres. Integrace s GitHubem a jeho nástroji pro správu projektů také umožňuje snadné sledování pokroku a komunikaci o jednotlivých úkolech a problémech, což vede k efektivnější koordinaci práce mezi různými členy týmu.

Při správě projektů v agilním vývoji se často setkáváme s výzvou, jak efektivně a rychle doručovat funkční iterace, které přinášejí hodnotu uživatelům. Je důležité se vyhnout rozptýlení na technické detaily, které nejsou přímo spojeny s uživatelskou hodnotou. Důraz by měl být kladen na to, aby výsledky vývoje měly konkrétní dopad na uživatele nebo klienty. K tomu slouží dobře definované kritéria pro přijatelnost, která zajistí, že každá nová verze bude splňovat konkrétní požadavky a potřeby.

Největší výzvou v každém vývojovém projektu je optimalizace našich zdrojů tak, abychom dosáhli co největšího dopadu s co nejmenšími náklady. Tato filozofie je základem aplikace principu 80/20, známého také jako Pareto princip. Tento princip říká, že 80% výsledků lze dosáhnout pouze s 20% úsilí. Při aplikaci tohoto principu na vývoj software to znamená, že bychom měli zaměřit naše úsilí na klíčové funkce, které přinesou největší užitek uživatelům, a minimalizovat náklady na neesenciální experimenty nebo nadměrné inženýrství.

Když se zaměříme na konkrétní typy aplikací, většina softwarových projektů spadá do kategorie aplikací pro podnikání (line-of-business apps, LOB). Tyto aplikace jsou klíčové pro fungování organizací a jejich vývoj je velmi častý. I když se může zdát, že se jedná o malé nebo středně velké aplikace, často se jejich složitost zvyšuje, jak roste rozsah funkcionality a velikost týmu. V takovém případě je nezbytné správně navrhnout architekturu, která umožní efektivní a škálovatelný růst aplikace, aniž by došlo k její nepřehlednosti nebo komplikacím při správě.

Důležité je také vědět, že s rostoucí složitostí aplikace je potřeba postupně přecházet na robustnější architektury a technologické stacky, které jsou schopné pokrýt rostoucí požadavky projektu. V tomto směru je nutné počítat s postupným zvyšováním technických nároků, které musí být splněny, aby aplikace mohla nadále fungovat efektivně.

Jak správně uzavřít outlet a implementovat tabulky s daty v Angularu

V některých případech se může stát, že router není schopen hladce uzavřít outlet. Tento problém lze efektivně vyřešit pomocí OutletCloserService, který se nachází ve společné složce aplikace a umožňuje uzavřít jakýkoliv outlet bez problémů z jakéhokoliv kontextu. Verze tohoto řešení byla původně vytvořena Andrewem Scottem, a podrobnosti o implementaci lze nalézt na tento odkaz.

Problém s životním cyklem komponenty a řešení s setTimeout

Kouzlo tohoto řešení se skrývá v životním cyklu komponenty Angularu. V metodě ngAfterViewInit se nejprve přihlásíme k událostem změny pro třídění (sorting) a stránkování (pagination), abychom mohli správně resetovat tabulku. Následně využijeme metodu merge v rámci volání setTimeout, jak je uvedeno ve výše zmíněném úryvku. Tento přístup nám umožňuje reagovat na změny v sortování, stránkování a filtraci, které ovlivňují data, jež se mají zobrazit.

Pokud dojde ke změně jakékoliv vlastnosti, celá pipeline je znovu spuštěna. Proč je však nutné použít setTimeout? Vzhledem k tomu, že používáme reference na paginator a sort, které jsou získány z šablony, musíme použít životní cyklus ngAfterViewInit. V tuto chvíli však Angular již nastavil vlastnost dataSource pro komponentu Material data table. Pokud bychom ji znovu přiřadili pomocí operátoru merge, vznikl by nám error NG0100 ExpressionChangedAfterItHasBeenCheckedError. Použití setTimeout posune přiřazení do dalšího cyklu detekce změn, čímž se tento problém vyřeší. Tento přístup je podobný tomu, jakým způsobem implementujeme proces přihlášení v AuthService.

Jak funguje načítání dat v tabulce?

Pipeline obsahuje volání metody this.userService.getUsers, která na základě aktuálních nastavení stránkování, třídění a filtrace získává uživatele. Výsledky jsou následně zpracovány a vloženy do Observable this.items$, ke kterému se komponenta tabulky přihlásí pomocí async pipe pro zobrazení dat. Není třeba se přímo přihlašovat k this.items$, protože komponenta tabulky to dělá automaticky. Pokud byste se přihlásili samostatně, každý dotaz na server by byl odeslán dvakrát.

Avšak je důležité dbát na správné umístění volání takeUntilDestroyed, které musí být na konci pipe. Jinak by mohlo docházet k úniku odběrů, pokud jsou merge operace prováděny po tomto volání.

Implementace potřebných modulů a CSS stylů

Pro správnou funkci tabulky je nutné importovat několik modulů. Patří sem například AsyncPipe, MatPaginatorModule, MatSortModule, nebo ReactiveFormsModule, které zabezpečují správné fungování asynchronních operací a komponent Material Design. Také nezapomeňte na správné implementování CSS stylů pro tabulku a její chování, například pro zobrazení načítacího spinneru nebo pro aplikaci efektů při výběru řádku.

CSS pro tabulku může vypadat následovně:

scss
.loading-shade {
position: absolute; top: 0; left: 0; bottom: 56px; right: 0; background: rgba(0, 0, 0, 0.15); z-index: 1; display: flex; align-items: center; justify-content: center; } .filter-row { min-height: 64px; padding: 8px 24px 0; } .full-width { width: 100%; } .mat-mdc-paginator { background: transparent; } .mat-mdc-row .mat-mdc-cell { border-bottom: 1px solid transparent; border-top: 1px solid transparent; cursor: pointer; } .mat-mdc-row:hover .mat-mdc-cell { border-color: currentColor; background-color: #efefef; } .selected { font-weight: 500; background-color: #efefef; }

Všimněte si například implementace třídy loading-shade, která pokrývá tabulku spinnerem při načítání dat. To je příklad lokalizovaného spinneru, který je vhodný pro větší aplikace, aby se zabránilo rušení uživatele globálním spinnerem. Později v části o implementaci globálního spinneru s NgRx/SignalState se dozvíte, jak tento přístup rozšířit na celou aplikaci.

Dynamické URL pro zobrazení detailu

V tabulce se nachází tlačítko pro zobrazení detailu uživatele. V šabloně je použito následujícího zápisu pro generování správného URL pomocí routerLink:

html
<mat-icon-button [routerLink]="['../users', { outlets: { detail: ['user', { userId: row._id }] } }]" skipLocationChange>

Tento zápis používá proměnnou row, která je kontextová pro každý řádek tabulky, a vytváří dynamické URL pro zobrazení detailu uživatele ve specifickém outletu. Použití relativní URL '../users' umožňuje komponentě tabulky, aby byla oddělena od kontextu modulu funkce, například /manager/users. To znamená, že komponentu lze znovu použít i v jiných modulech, jako je /owner/users nebo /ceo/users, bez nutnosti pevně kódovaných cest.