Çapraz Platform Proje Yapısı: Kod Organizasyonunda Best Practice

Flutter veya React Native'de kod organizasyonu, projenin ölçeklenebilirliğini ve bakımını doğrudan etkiler. Kötü yapı, ekip içinde karışıklığa, kod tekrarına ve hata ayıklamada zorluklara yol açar.

Öneri olan yapı her özelliği (feature) kendi klasörüne koymaktır:

1lib/
2├── features/
3│ ├── auth/
4│ │ ├── data/
5│ │ │ ├── datasources/
6│ │ │ ├── models/
7│ │ │ └── repositories/
8│ │ ├── domain/
9│ │ │ ├── entities/
10│ │ │ ├── repositories/
11│ │ │ └── usecases/
12│ │ └── presentation/
13│ │ ├── bloc/ (veya provider)
14│ │ ├── pages/
15│ │ └── widgets/
16│ ├── home/
17│ └── profile/
18├── core/
19│ ├── constants/
20│ ├── utils/
21│ ├── theme/
22│ └── network/
23└── main.dart

Hem Android hem iOS'ta çalışan mantığı core/ klasöründe tutun. Platform-spesifik kod ise android/ ve ios/ klasörlerinde kalır.

Bir sayaç uygulamasında yapı şöyle olur:

Reklam · TEST
AdSense Test ReklamıYazı arası (gönderi içi) · Yazı arası

lib/features/counter/presentation/bloc/counter_bloc.dart:

1import 'package:flutter_bloc/flutter_bloc.dart';
2
3class CounterBloc extends Bloc<CounterEvent, int> {
4CounterBloc(): super(0) {
5on<IncrementEvent>((event, emit) {
6emit(state + 1);
7});
8on<DecrementEvent>((event, emit) {
9emit(state - 1);
10});
11}
12}
13
14abstract class CounterEvent {}
15class IncrementEvent extends CounterEvent {}
16class DecrementEvent extends CounterEvent {}

lib/features/counter/presentation/pages/counter_page.dart:

1import 'package:flutter/material.dart';
2import 'package:flutter_bloc/flutter_bloc.dart';
3import '../bloc/counter_bloc.dart';
4
5class CounterPage extends StatelessWidget {
6@override
7Widget build(BuildContext context) {
8return Scaffold(
9appBar: AppBar(title: Text('Sayaç')),
10body: Center(
11child: BlocBuilder<CounterBloc, int>(
12builder: (context, count) {
13return Text('Sayı: $count', style: TextStyle(fontSize: 32));
14},
15),
16),
17floatingActionButton: Row(
18mainAxisAlignment: MainAxisAlignment.end,
19children: [
20FloatingActionButton(
21onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
22child: Icon(Icons.add),
23),
24SizedBox(width: 10),
25FloatingActionButton(
26onPressed: () => context.read<CounterBloc>().add(DecrementEvent()),
27child: Icon(Icons.remove),
28),
29],
30),
31);
32}
33}

Beklenen çıktı: Sayfa açıldığında "Sayı: 0" görünür. Artı butonuna basınca 1, eksi butonuna basınca -1 olur.

  • Dart dosyaları: snake_case (örn: counter_bloc.dart)
  • Sınıf adları: PascalCase (örn: CounterBloc)
  • Değişkenler: camelCase (örn: counterValue)

İyi bir yapı, geliştiricilerin hızlı yer bulmasını sağlar. Feature-based klasörleme, Clean Architecture ilkelerine uygun bir yaklaşımdır. Küçük projeler için basit tutabilir, büyüdükçe bu yapıya geçiş kolay olur.

Reklam · TEST
AdSense Test ReklamıGönderi altı · Görüntülü
konu hakkında tepkinizi verebilirsiniz

5 yorum

  • adlı kullanıcıya yanıt verdi
    yarisiyolda

    doğru bence de o yüzden şeyi automatize etmek lazım linter ya da code generation tool

  • adlı kullanıcıya yanıt verdi
    uykuarasi

    template hazırlamak güzel ama sonra kimse okumaz be dosya şablonu falan da kimse kullanmaz gerçek hayatta

  • adlı kullanıcıya yanıt verdi
    yarisiyolda

    aynen bu yüzden baştan bir template veya convention document hazırlamak gerekiyor yoksa 3 ay sonra her klasörde farklı bir sistem oluyor

  • uykuarasi

    hadi canım feature başına klasör açmak doğru ama sonra herkes kendi proje yapısını

  • adlı kullanıcıya yanıt verdi
    uykuarasi

    linter falan da kurulur ama takım bunu ignore etmeye başlayınca ne faydası kalır ya ya da