Live coding və code review ssenariləri
Live coding mərhələsində məqsəd işləyən kod deyil — düşüncə prosesini səsli göstərməkdir. İşləyən struktur:
1. Tələbi dəqiqləşdir (30 saniyə): "Bu ekran offline işləməlidir? Yükləmə zamanı köhnə məlumat qalmalıdır? Səhifələmə var?"
2. Modeli əvvəlcə yaz: state sinfi və onun mümkün vəziyyətləri. Bu, müsahibə "state modelləşdirməni bilir" siqnalı verir.
3. UI-ı sonra: state-dən UI-a keçid switch/pattern matching ilə.
4. Xəta və boş vəziyyəti unutma — namizədlərin çoxu yalnız uğurlu yolu yazır; bu, ən tez görünən fərqdir.
5. Testi ən azı ağızda de: "Bu notifier üçün ilk testim boş siyahı halı olardı."
6. Trade-off-u səsləndir: "Burada optimistik yenilənmə seçdim, çünki əməliyyat geri qaytarıla biləndir."
// 1) Model: mümkün olmayan vəziyyətlər ifadə edilə bilməz.
// AsyncValue loading/error/data-nı özü daşıyır, ona görə əlavə model lazım deyil.
// 2) State qatı.
class Articles extends AsyncNotifier<List<Article>> {
@override
Future<List<Article>> build() {
return ref.watch(articleRepositoryProvider).fetchAll();
}
Future<void> refresh() async {
state = const AsyncLoading<List<Article>>().copyWithPrevious(state);
state = await AsyncValue.guard(
() => ref.read(articleRepositoryProvider).fetchAll(),
);
}
}
final articlesProvider =
AsyncNotifierProvider<Articles, List<Article>>(Articles.new);
// 3) UI: dörd hal — data, boş, xəta, ilk yükləmə.
class ArticlesPage extends ConsumerWidget {
const ArticlesPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final articles = ref.watch(articlesProvider);
return Scaffold(
body: RefreshIndicator(
onRefresh: () => ref.refresh(articlesProvider.future),
child: switch (articles) {
AsyncValue(:final value?) when value.isEmpty =>
const EmptyView(message: 'Hələ məqalə yoxdur'),
AsyncValue(:final value?) => ArticleListView(items: value),
AsyncValue(:final error?) => ErrorView(
message: '$error',
onRetry: () => ref.invalidate(articlesProvider),
),
_ => const ArticleSkeleton(),
},
),
);
}
}Tipik tapşırıq: siyahı + yükləmə + xəta + "yenidən yoxla". Riverpod variantı.
enum ArticlesStatus { initial, loading, success, failure }
final class ArticlesState extends Equatable {
const ArticlesState({
this.status = ArticlesStatus.initial,
this.items = const [],
this.error,
});
final ArticlesStatus status;
final List<Article> items;
final String? error;
ArticlesState copyWith({
ArticlesStatus? status,
List<Article>? items,
String? error,
}) => ArticlesState(
status: status ?? this.status,
items: items ?? this.items,
error: error,
);
@override
List<Object?> get props => [status, items, error];
}
sealed class ArticlesEvent {}
final class ArticlesStarted extends ArticlesEvent {}
final class ArticlesRefreshRequested extends ArticlesEvent {}
class ArticlesBloc extends Bloc<ArticlesEvent, ArticlesState> {
ArticlesBloc(this._repository) : super(const ArticlesState()) {
on<ArticlesStarted>(_onLoad);
// Təkrar sorğuların qarşısını alır.
on<ArticlesRefreshRequested>(_onLoad, transformer: droppable());
}
final ArticleRepository _repository;
Future<void> _onLoad(ArticlesEvent event, Emitter<ArticlesState> emit) async {
emit(state.copyWith(status: ArticlesStatus.loading, error: null));
try {
final items = await _repository.fetchAll();
emit(state.copyWith(status: ArticlesStatus.success, items: items));
} catch (error) {
// Köhnə items saxlanılır: ekran boşalmır.
emit(state.copyWith(status: ArticlesStatus.failure, error: '$error'));
}
}
}Eyni tapşırıq, BLoC variantı — status enum ilə.
| Code review-da red flag | Niyə problem |
|---|---|
| `build` metodunda `Navigator`, `showDialog`, `showSnackBar` | Rebuild təkrarlandıqda effekt təkrarlanır |
| `build`-də `read`/`context.read<T>().state` ilə dəyər oxumaq | Abunəlik yoxdur — UI köhnə dəyərlə qalır (sənəd bunu "səhvə meyllidir" adlandırır) |
| State-in kolleksiyasını yerində dəyişmək (`items.add(...)`) | `==` fərq görmür: bloc-da dəyişiklik udulur, `select` filtri işləmir |
| `Equatable`-da `props`-a yeni sahənin əlavə edilməməsi | İki fərqli state bərabər sayılır — səssiz bug |
| Notifier/provider-in `build` metodunda yaradılması | Hər rebuild-də yeni obyekt: state itir, köhnəsi sızır |
| `await`-dan sonra `mounted` yoxlanışı olmadan `context` | Söküləmiş widget-də crash; lint qaydası bunu tutur |
| Ephemeral state (form, scroll) üçün qlobal provider | Geniş rebuild və route-lar arası state sızması; Riverpod sənədi buna qarşı xəbərdarlıq edir |
| Kritik axında transformer-in göstərilməməsi | İki dəfə basılış → iki sifariş/ödəniş |
Live coding-də ən çox itirilən bal — xəta və boş vəziyyətin yazılmamasıdır. Yalnız uğurlu yolu yazan namizədlə dörd halı (ilk yükləmə, boş, xəta, yenidən yükləmə) nəzərə alan namizəd arasındaki fərq kod keyfiyyətindən çox məhsul düşüncəsi kimi qiymətləndirilir. Bir cümlə kifayətdir: "Boş siyahı və xəta ekranı da lazımdır — onları da əlavə edirəm."
📚 Mənbələr və sənədlər
- Flutter arxitekturası: case studyrəsmidocs.flutter.dev
Real kodda layer-lərin necə göründüyü — live coding üçün yaxşı nümunə.
- Riverpod: pull-to-refreshrəsmiriverpod.dev
- Bloc: state modelləşdirmərəsmibloclibrary.dev
- Flutter: test icmalırəsmidocs.flutter.dev