Fiche 17.03 — Projet fil-rouge : une app complète à construire (et à mettre en portfolio)
Objectif
Construire UNE app de bout en bout, incrément par incrément, en suivant les parties du cours. À la fin tu as un repo GitHub propre, taggé jalon par jalon, que tu peux montrer en entretien ou à un client freelance. Tu sais déjà coder : ici on capitalise pour produire une preuve d'embauche.
1. Pourquoi un projet fil-rouge (et pas 10 mini-démos)
Un recruteur ne lit pas ton CV en détail, il regarde ton GitHub 90 secondes. Dix dépôts à moitié finis disent "junior". Un seul repo cohérent, testé, avec une vraie archi et un historique de commits propre dit "je sais livrer".
Le but n'est pas de faire joli, c'est de prouver des compétences que les offres exigent : MVVM testable, async/await, persistance offline, backend, sécurité, publication. Chaque jalon coche une case d'une fiche de poste.
Réflexe UIKit -> tu avais ton "projet de stage" avec storyboards + delegates. Ici l'équivalent moderne, c'est un repo SwiftUI + @Observable + SwiftData, vendable tel quel.
2. Choisir ton app (3 candidats portfolio-friendly)
Choisis-en une seule. Critère : assez riche pour montrer du réseau + persistance + auth, assez petite pour la finir.
Conseil : prends celle dont tu comprends le métier (tu fais du sport -> Workout). Tu poseras de meilleures décisions produit, et tu sauras en parler en entretien.
Évite : un clone d'app connue ("mon Instagram"), un truc sans données (calculatrice), ou trop ambitieux (réseau social complet). Un client freelance veut voir que tu sais cadrer un scope.
3. La stack imposée (non négociable, c'est elle qui te rend crédible)
Pourquoi cette stack : c'est exactement ce que demandent les offres iOS 2025-2026. Tu n'inventes rien d'exotique, tu montres que tu maîtrises le standard moderne.
4. Architecture cible (le schéma à savoir dessiner)
Règles :
- La View ne connaît que son ViewModel. Pas de logique réseau dans la View.
- Le ViewModel ne connaît que des protocoles de services (donc mockable en test).
- Le service décide : cache SwiftData d'abord, puis réseau (offline-first).
- Le Router centralise la navigation, les écrans ne se poussent pas entre eux.
Réflexe UIKit -> ton Coordinator devient un Router observable qui pousse des routes enum dans le path du NavigationStack. "Pas idéal" : naviguer avec des NavigationLink éparpillés. "Préférable" : un enum Route + router.push(.detail(id)).
5. Les jalons (un commit + un tag par étape)
Chaque partie du cours ajoute une couche. Tu commits, tu tags, tu pousses. À la fin l'historique raconte ta montée en compétence.
Discipline Git (montre que tu sais bosser en équipe) :
"Pas idéal" : un seul commit géant "projet final". "Préférable" : des commits atomiques avec messages conventionnels (feat:, fix:, test:, refactor:), branches par feature.
6. Backend : Firebase ou Supabase (choisis, ne mélange pas)
Pour le portfolio, l'un ou l'autre est crédible. Supabase te fait gagner des points si l'offre mentionne SQL/Postgres ; Firebase si elle veut du temps réel rapide. Décide AU JALON J4 et assume le choix en entretien (savoir justifier > savoir les deux à moitié).
Erreur fréquente : laisser les règles de sécurité backend en mode "test" (tout ouvert). En entretien c'est éliminatoire. Écris des règles : un user ne lit/écrit que SES données.
7. Sécurité minimale (jalon J8, ce que les recruteurs vérifient)
Réflexe UIKit -> tu stockais peut-être un token dans NSUserDefaults. "Pas idéal" aujourd'hui. "Préférable" : Keychain avec kSecAttrAccessibleWhenUnlockedThisDeviceOnly (exclu des backups iCloud, cf. fiche 09.03). Le Privacy Manifest est obligatoire pour publier depuis le 1er mai 2024 : sans déclaration correcte des Required Reason APIs (y compris pour les SDK tiers), rejet automatique à l'upload. Deux règles de review souvent oubliées : 5.1.1(v) impose une suppression de compte accessible dans l'app dès que l'inscription y est possible ; 4.8 exige de proposer Sign in with Apple si tu offres un login social tiers (Google/Facebook).
Vérifie qu'aucun secret n'est dans l'historique Git :
8. Le README pro (c'est lui qu'on lit, pas ton code)
Structure qui fait pro :
Les captures comptent énormément : ajoute 3-4 images dans /Screenshots et intègre-les. Un repo iOS sans capture = personne ne clique.
9. Le pitch d'archi de 2 minutes (à répéter à l'oral)
En entretien on te dira "présente un projet". Prépare 2 min chrono :
Montrer que tu connais les limites de ton archi vaut plus que de prétendre que tout est parfait. C'est le réflexe d'un dev senior.
10. Se vendre en freelance (le volet business)
Le repo fil-rouge sert double : preuve de compétence ET base de code que tu peux réutiliser pour démarrer une mission rapidement.
11. Idées de features bonus (pour pousser plus loin)
Si tu veux te démarquer, ajoute 1-2 de ces features (pas toutes) :
La CI (#8) est sous-estimée : un badge "tests passing" sur ton README impressionne plus qu'une feature de plus.
Points à connaître
- Scope creep. L'erreur n°1 : ajouter des features avant d'avoir fini le coeur. Termine J0->J9 sur un scope minimal AVANT les bonus. Un projet fini > un projet riche inachevé.
- Commits propres dès J0. Ne te dis pas "je nettoierai l'historique après". Personne ne le fait. Messages conventionnels et branches dès le premier jour.
- Secrets committés. Un
GoogleService-Info.plistou une clé Supabase dans l'historique Git est public à vie (même supprimé après). Mets-les dans.gitignoreAVANT le premier commit, fournis un*.example. - Tests "décoratifs". Tester
1+1==2ne compte pas. Teste la vraie logique : pagination, gestion d'erreur réseau, transition d'état du ViewModel. La couverture du coeur métier est ce qu'on regarde. - Suppression de compte oubliée. Si l'app permet de créer un compte, Apple exige (règle 5.1.1(v)) un bouton de suppression DANS l'app — un simple "contactez le support" est refusé. Prévois-la dès J4, pas la veille de la soumission.
Exercice (15-20 min)
- Choisis ton app parmi les 3 (§2) ou une variante que tu maîtrises. Note en une phrase le problème qu'elle résout.
- Écris ton README initial (
README.md) avec : le pitch (2 lignes), la liste de features (5 max), la stack imposée (§3), et une section "Architecture" même vide pour l'instant. - Crée le repo GitHub et fais ton premier commit :
- Épingle le repo sur ton profil GitHub.
Livrable : un repo public avec un README qui pitch ton app et un premier tag v0.1. Tu construiras le reste jalon par jalon en avançant dans le cours.
Question d'entretien
Q1 — "Présente-moi un projet perso et explique ton architecture."
"J'ai construit [WorkoutTracker], une app de suivi d'entraînements utilisable hors-ligne. Côté archi : SwiftUI pour l'UI, des ViewModels
@Observablequi portent la logique, et des services injectés par protocole — ce qui me permet de tester la logique sans lancer l'UI. La navigation passe par un Router enum dans unNavigationStack. Pour les données, je suis offline-first : je lis SwiftData d'abord, puis je synchronise avec Supabase en arrière-plan. J'ai choisi Supabase car mes données sont relationnelles. Mes tokens sont en Keychain, j'ai un Privacy Manifest pour la publication. La limite assumée : la résolution de conflits de sync est en last-write-wins."
Q2 — "Pourquoi @Observable plutôt qu'ObservableObject ?"
"
@Observable(Observation framework, iOS 17+) est plus performant : SwiftUI ne réévalue que les vues qui lisent réellement une propriété modifiée, alors qu'ObservableObjectnotifie tout abonné àobjectWillChange. C'est aussi moins de boilerplate : plus de@Publishedni de@StateObject, juste@Stateou@Bindable. Je gardeObservableObjectuniquement pour du code legacy ou si je dois supporter iOS 16."
Q3 — "Comment garantis-tu que ton ViewModel est testable ?"
"Le ViewModel ne dépend jamais d'une implémentation concrète, seulement de protocoles (
WorkoutServiceProtocol). En production j'injecte le vrai service, en test un mock qui renvoie des données ou des erreurs contrôlées. Je peux ainsi tester chaque transition d'état — loading, loaded, empty, error — de façon déterministe, y compris le code async avec Swift Testing."
Résumé
- Un seul projet fil-rouge cohérent > dix démos inachevées : c'est ta preuve d'embauche.
- Choisis une app dont tu comprends le métier (Workout, Recipe ou Expense) avec un scope cadré.
- Stack imposée et crédible : SwiftUI + @Observable + MVVM testable + async/await + Router + SwiftData + backend (Firebase OU Supabase) + tests + sécurité.
- Construis par jalons J0->J9 alignés sur les parties du cours, un commit + un tag par jalon.
- Backend : choisis Firebase OU Supabase, ne mélange pas, et sache justifier le choix.
- Sécurité (J8) : Keychain (
...ThisDeviceOnly), Privacy Manifest, zéro secret committé, règles backend strictes, suppression de compte (5.1.1(v)) et Sign in with Apple (4.8) si login social. - Livrable final : repo GitHub public, README pro avec captures, pitch d'archi de 2 min répété.
- Volet freelance : épingle le repo, vends les bénéfices (pas la techno), découpe tes devis en jalons.
- Finis le coeur AVANT les bonus (widget, watchOS, CI, App Intents).