Lemme 2
CampusGuide
Une application Android pour s'orienter sur les deux campus de Concordia : itinéraires extérieurs et intérieurs, navette, et trajet vers le prochain cours.
Écrans
- MapPavillons, itinéraires, navette
- Indoor mapÉtages et salles
- CalendarHoraire, prochain cours
- Points of interest
- Accessibility
État
- ViewModelsRecherche, position, navigation intérieure, calendrier
Domaine et données
- Directions repositories
- Indoor pathfindingDijkstra
- ShuttleTracker
- GeoJSON parser
- CalendarRepository
Services externes
- Google Maps SDK
- Google Routes API
- Concordia Open Data API
Aperçu
CampusGuide est une application de navigation pour les campus Sir George Williams et Loyola de l'Université Concordia, réalisée en une session par une équipe de onze personnes, The Null Pointers. Elle dessine les pavillons sur une carte, propose des itinéraires extérieurs selon plusieurs modes de déplacement, guide à l'intérieur d'une salle à l'autre et d'un étage à l'autre, connaît l'horaire de la navette et peut mener un étudiant de sa position jusqu'à son prochain cours.
J'étais l'un des cinq développeurs du volet frontal de l'équipe. Cette page décrit l'application dans son ensemble, puis distingue les parties que j'ai réalisées.
Problème
Un horaire donne à l'étudiant un code de pavillon et un numéro de salle, sur l'un des deux campus séparés de plusieurs kilomètres. Une application de cartographie générale s'arrête à la porte d'entrée : elle ignore à quel étage se trouve la salle, quand part la prochaine navette entre les campus et quel cours vient ensuite.
Objectifs
- Afficher les deux campus en distinguant nettement leurs pavillons du reste de la ville, et passer de l'un à l'autre d'un seul geste.
- Proposer des itinéraires extérieurs à pied, en voiture, en transport en commun et avec la navette de Concordia, y compris d'un campus à l'autre.
- Guider à l'intérieur entre des salles situées à des étages différents, avec des options tenant compte de l'accessibilité.
- Lire l'horaire de cours d'un étudiant et proposer un itinéraire vers son prochain cours.
Technologies
| Application | Kotlin, Jetpack Compose, Material 3, Google Maps SDK for Android, Maps Compose, Play Services Location, Google Routes API, Concordia Open Data API, Retrofit, OkHttp, kotlinx.serialization, DataStore |
|---|---|
| Tests | JUnit 4, Robolectric, Mockito, MockWebServer, kotlinx-coroutines-test, Compose UI Test, Espresso, UI Automator |
| Build et intégration continue | Gradle (Kotlin DSL), GitHub Actions, JaCoCo, SonarQube Cloud, Android Lint |
Architecture
Une application Jetpack Compose à activité unique. Les écrans et les composables réutilisables reposent sur des ViewModels qui détiennent l'état de l'interface. Des dépôts de données encapsulent les services externes : l'API Routes de Google pour les itinéraires extérieurs et l'API de données ouvertes de Concordia pour les horaires de cours.
Les pavillons sont des polygones GeoJSON, analysés puis dessinés en surimpression sur la carte. La navigation intérieure constitue un moteur à part, réalisé par des coéquipiers : des graphes d'étage chargés depuis les ressources, l'algorithme de Dijkstra pour le plus court chemin sur un étage, et un routeur qui relie les étages entre eux.
La navette est modélisée par une classe du domaine placée derrière une interface de source de données : sa logique d'horaire se teste ainsi sans carte à l'écran.
Mes responsabilités
Un projet d'équipe de onze membres. J'ai travaillé au volet frontal et mis en place une bonne partie de l'outillage de build, de test et de couverture. Voici ce que j'ai réalisé, dans l'ordre d'arrivée :
- Fondations : la première intégration de Google Maps, les workflows GitHub Actions et le rapport de couverture JaCoCo vers SonarQube Cloud.
- Changement de campus : le sélecteur entre les deux campus, la mémorisation du campus choisi, l'animation de la caméra et le remplacement des polygones de pavillons.
- Itinéraires d'un campus à l'autre, entre Sir George Williams et Loyola, avec des tests de bout en bout qui ne dépendent pas du GPS de l'appareil.
- Le panneau d'itinéraire étape par étape, qui se déplie et se replie.
- Arrêts de navette : la classe de domaine ShuttleTracker, les marqueurs d'arrêt sur la carte et la fiche d'information d'un arrêt.
- L'itinéraire vers le prochain cours à partir de l'horaire du jour, et les tests d'acceptation des fonctions de calendrier.
100 des 507 commits (hors fusions) de la branche main sont les miens. La navigation intérieure, les points d'intérêt et les écrans d'accessibilité ont été réalisés par des coéquipiers.
Décisions d'ingénierie
Analyser hors du fil principal, afficher sur celui-ci
Les polygones des pavillons proviennent de fichiers GeoJSON assez volumineux pour figer l'interface lorsqu'ils sont analysés au démarrage. J'ai déplacé l'analyse des coordonnées vers un répartiteur d'arrière-plan, conservé les appels à la carte sur le fil principal, comme l'exige le SDK Maps, et chargé la surimpression de chaque campus seulement à son premier affichage.
Des tests unitaires rapides plutôt que lourds
La couverture initiale reposait sur des tests Robolectric qui démarraient des activités entières. Ils étaient lents et épuisaient la mémoire de la suite. J'en ai supprimé 203 et changé d'approche : la logique est extraite dans des méthodes à la portée de simples tests unitaires, et des tests instrumentés couvrent ce qui exige réellement l'environnement d'exécution de Compose.
Une classe de domaine avant tout marqueur
Pour la navette, j'ai d'abord extrait une classe ShuttleTracker et un modèle d'arrêt derrière une interface de source de données, puis seulement dessiné les marqueurs et la fiche d'information par-dessus. La logique d'horaire est couverte par des tests unitaires qui ne touchent jamais à une carte.
Mesurer le code qui peut être mesuré
Le code de mise en page des composables et l'affichage de la carte ne peuvent pas être exercés par des tests unitaires. J'ai exclu ces couches du calcul de couverture, pour que le seuil de qualité porte sur la logique réellement atteignable par des tests unitaires, et j'ai consigné ce raisonnement dans le guide de test du dépôt.
Tests et qualité
La branche main compte 831 méthodes de test unitaire réparties dans 63 fichiers et 72 méthodes de test instrumenté dans 27 fichiers. Les tests unitaires s'appuient sur JUnit 4, Robolectric et Mockito; les tests instrumentés, sur Compose UI Test et Espresso, sont pour la plupart rédigés comme des tests d'acceptation numérotés.
Quatre workflows GitHub Actions construisent l'application, exécutent les tests unitaires et Android Lint, produisent le rapport JaCoCo destiné à SonarQube Cloud et génèrent un APK de publication.
Défis
L'application figeait au chargement de la carte
L'ajout du second campus a rendu l'écran de la carte inerte au démarrage. La cause : l'analyse du GeoJSON sur le fil principal. La déplacer a réglé le gel et révélé le problème suivant : attacher les surimpressions depuis un fil d'arrière-plan faisait planter l'application, car le SDK Maps ne fonctionne que sur le fil principal. La version finale analyse en arrière-plan et attache sur le fil principal.
Une suite de tests à court de mémoire
À mesure que les tests de couverture s'accumulaient, la suite s'est mise à échouer faute de mémoire, et les tests se perturbaient entre eux par des simulacres statiques et des portées de coroutines partagées. Augmenter la mémoire allouée a fait gagner du temps; la vraie solution a consisté à retirer les tests lourds, à remplacer les simulacres statiques par des points d'injection et à empêcher les portées de coroutines de déborder d'un test à l'autre.
Rapport de couverture sur une nouvelle chaîne de build
Le projet utilisait la version 9 du plugin Android Gradle, avec laquelle la configuration habituelle de JaCoCo et de SonarQube ne fonctionnait pas. Faire apparaître la couverture dans le seuil de qualité a demandé plusieurs itérations sur les chemins de classes, l'enchaînement des tâches et des sources indexées en double.
Résultats
| Mesure | Résultat | Source |
|---|---|---|
| Livré | Cartes des campus, itinéraires extérieurs et intérieurs, navette, horaire et points d'intérêt | Arborescence du code sur la branche main |
| Tests unitaires | 831 méthodes de test dans 63 fichiers | Compté sur la branche main, avril 2026 |
| Tests instrumentés | 72 méthodes de test dans 27 fichiers | Compté sur la branche main, avril 2026 |
| Ma part de l'historique | 100 commits sur 507, hors fusions | Historique Git de la branche main |
Tableau 1. Les chiffres de tests sont comptés à partir des annotations de test dans le code, et non d'un rapport d'exécution. Aucun pourcentage de couverture n'est cité, car le dépôt ne contient pas de rapport final mesuré.
Dépôt et liens
ShadiiAM/ConcordiaCampusGuide(ouvre un nouvel onglet)
Le dépôt de l'équipe, hébergé sur le compte d'un coéquipier. Mes commits y figurent sous ma propre identité GitHub.
Ce projet n'a pas de démo hébergée. Le dépôt explique comment l'exécuter.
Fin de l'étude de cas