Content

Optimiser ses scripts Google Apps Script avec Gemini

Guide pratique pour optimiser vos scripts Google Apps Script avec Gemini : prompts efficaces, refactorisation testable, batch I/O, cache, gestion des quotas, debugging, sécurité et exemples de code prêts à adapter.

Gemini peut devenir votre copilote pour écrire, refactorer et fiabiliser des scripts Google Apps Script (GAS). L’objectif n’est pas seulement de “générer du code”, mais d’obtenir des scripts plus rapides, plus robustes et plus faciles à maintenir. Voici une méthode concrète, du brief au déploiement, avec des exemples prêts à l’emploi.

Quand utiliser Gemini dans votre flux de travail

Utilisez Gemini à trois moments clés : au démarrage pour transformer un besoin métier en squelette de script, pendant l’itération pour diagnostiquer et corriger, et en fin de cycle pour documenter, tester et accélérer les performances. Cette boucle courte vous évite de “bricoler” à l’aveugle et réduit les aller-retours avec l’éditeur.

Poser un brief clair qui produit du bon code

Un prompt efficace décrit la source des données (Sheets, Drive, Gmail, Calendar), l’action attendue, les contraintes de performance et le format de sortie. Précisez toujours les limites (quota, volumes, latence).

Exemple de brief utile :

“Écris un script Apps Script qui lit 5 000 lignes d’une feuille ‘Leads’ (colonnes A:D), nettoie les emails, enrichit la colonne ‘domaine’ et alimente une feuille ‘Scores’. Le script doit fonctionner en moins de 5 minutes, utiliser getValues() en bloc, ne pas faire de setValue en boucle, et logguer le temps d’exécution.”

Gemini génèrera un premier jet que vous pourrez ensuite optimiser.

Modèle de squelette prêt à améliorer

Commencez avec un modèle minimaliste que Gemini adaptera à votre cas :

function main() {
  const started = Date.now();
  const ss = SpreadsheetApp.getActive();
  const src = ss.getSheetByName('Leads');
  const dst = ss.getSheetByName('Scores') || ss.insertSheet('Scores');

  const values = src.getDataRange().getValues(); // lecture en bloc
  const header = values.shift();

  const out = [ ['email','domaine','score'] ];
  for (const row of values) {
    const email = String(row[0]).trim().toLowerCase();
    if (!email || !/@/.test(email)) continue;

    const domaine = email.split('@')[1] || '';
    const score = scoreFromDomain_(domaine); // fonction pure à implémenter
    out.push([email, domaine, score]);
  }

  dst.clearContents();
  dst.getRange(1,1,out.length,out[0].length).setValues(out);
  Logger.log(`Done in ${Date.now() - started} ms`);
}

function scoreFromDomain_(d) {
  if (!d) return 0;
  if (d.endsWith('.edu')) return 90;
  if (d.includes('gmail') || d.includes('yahoo')) return 10;
  return 50;
}

Demandez ensuite à Gemini d’optimiser des points précis : gestion d’erreurs, séparation logique, instrumentation, contrôles d’entrées.

Réécrire du code procédural en fonctions pures

La maintenabilité passe par des fonctions pures, testables et sans effets de bord. Collez votre code existant dans Gemini en lui demandant de :

  • découper en petites fonctions (lecture, transformation, écriture),

  • retirer les getValue() / setValue() dans les boucles au profit de batch,

  • isoler la logique métier pour pouvoir la tester sans Google Services.

Prompt type :

“Transforme ce script pour qu’il n’appelle Sheets qu’en lecture/écriture groupée, sépare la logique métier en fonctions pures, et ajoute un validateRow(row) qui retourne une erreur descriptive si les données sont invalides.”

Accélérer les scripts : 7 leviers concrets

  1. Batcher l’I/O : lire et écrire en blocs (getValues() / setValues()), pas dans la boucle.

  2. Limiter les appels aux services : regrouper les accès Drive, Gmail, Calendar.

  3. Éviter les conversions répétées : parsez une fois, passez des références.

  4. Préférer les maps/sets pour les recherches rapides sur des listes.

  5. Mémoriser des informations calculées fréquentes (cache).

  6. Arrêter tôt si un seuil temps est dépassé, et planifier une reprise.

  7. Logger le temps par étape pour repérer les goulots d’étranglement.

Exemple d’instrumentation simple :

function withTimer_(label, fn) {
  const t0 = Date.now();
  const r = fn();
  Logger.log(`${label}: ${Date.now() - t0} ms`);
  return r;
}

// Usage
function main() {
  const data = withTimer_('read', () => readLeads_());
  const enriched = withTimer_('transform', () => transform_(data));
  withTimer_('write', () => writeScores_(enriched));
}

Utiliser efficacement le cache

Le CacheService évite de recalculer des valeurs coûteuses (lookup externe, regex complexes). Gemini peut ajouter ce pattern à vos fonctions.

function cached_(key, ttlSec, producer) {
  const cache = CacheService.getScriptCache();
  const hit = cache.get(key);
  if (hit !== null) return JSON.parse(hit);
  const val = producer();
  cache.put(key, JSON.stringify(val), ttlSec);
  return val;
}

Appel type : cached_('domainRules', 3600, loadRulesFromSheet_).

Gérer les quotas et les limites de temps

GAS impose des limites quotidiennes et un temps d’exécution (~6 minutes typiquement). Gemini peut vous proposer un mécanisme de reprise.

  • Chunking : traitez par paquets (ex. 1 000 lignes), stockez l’offset dans PropertiesService.

  • Déclencheur continu : créez un trigger temporaire pour continuer après la fenêtre.

function processBatch() {
  const props = PropertiesService.getScriptProperties();
  const offset = parseInt(props.getProperty('OFFSET') || '0', 10);
  const size = 1000;

  const { rows, done, nextOffset } = readChunk_(offset, size);
  const out = transform_(rows);
  writeChunk_(out, offset);

  if (!done) {
    props.setProperty('OFFSET', String(nextOffset));
    ScriptApp.newTrigger('processBatch').timeBased().after(10 * 1000).create();
  } else {
    props.deleteAllProperties();
  }
}

Demandez à Gemini de générer les fonctions readChunk_ et writeChunk_ adaptées à votre feuille.

Debugging assisté : faire expliquer les erreurs

Copiez le message d’erreur et le bloc de code fautif. Demandez à Gemini une explication d’abord, puis une correction raisonnée. Contraignez la réponse : “explique la cause probable”, “propose un patch minimal”, “ne change pas les signatures de fonctions”.

Prompt type :

“Voici l’erreur ‘TypeError: Cannot read properties of null (reading getDataRange)’, voici la fonction concernée. Explique la cause racine la plus probable, propose une correction minimale et un test rapide pour valider.”

Refactoriser vers un style testable

Même si GAS n’a pas de framework de tests natif, vous pouvez isoler la logique pure et la tester via une feuille dédiée ou un petit harnais.

function test_transform_() {
  const sample = [
    ['email','name'],
    ['alice@exemple.com','Alice'],
    ['','Bob'],
  ];
  const out = transform_(sample);
  Logger.log(JSON.stringify(out, null, 2));
  // Attendu : aucune ligne vide, emails normalisés
}

Demandez à Gemini de fournir 5 cas de test représentatifs (emails invalides, doublons, caractères spéciaux, champs manquants).

Patterns utiles pour Sheets, Drive, Gmail

Lecture/écriture Sheets fiable

function readRange_(sheetName) {
  const sh = SpreadsheetApp.getActive().getSheetByName(sheetName);
  if (!sh) throw new Error(`Sheet ${sheetName} introuvable`);
  const values = sh.getDataRange().getValues();
  const header = values.shift();
  return { header, rows: values };
}

function writeMatrix_(sheetName, matrix) {
  const ss = SpreadsheetApp.getActive();
  const sh = ss.getSheetByName(sheetName) || ss.insertSheet(sheetName);
  sh.clearContents();
  sh.getRange(1,1,matrix.length,matrix[0].length).setValues(matrix);
}

Recherche Drive rapide

function listPdfsInFolder_(folderId, limit=100) {
  const folder = DriveApp.getFolderById(folderId);
  const files = folder.getFilesByType(MimeType.PDF);
  const res = [];
  while (files.hasNext() && res.length < limit) {
    const f = files.next();
    res.push([f.getName(), f.getId(), f.getSize()]);
  }
  return res;
}

Traitement Gmail par lots

function archiveOldNewsletters_() {
  const threads = GmailApp.search('label:newsletter older_than:30d', 0, 200);
  GmailApp.moveThreadsToArchive(threads);
  Logger.log(`Archivés: ${threads.length}`);
}

Demandez à Gemini d’ajouter des garde-fous (labels exclus, whitelists de domaines).

Sécurité et permissions : les bons réflexes

  • Scopes minimaux : n’activez que les services nécessaires.

  • Vérifications d’entrée : validez les emails, IDs, tailles de fichiers.

  • Journalisation : logguez sans stocker de données sensibles.

  • Rôles : si vous publiez un add-on, documentez clairement ce que le script peut faire.

Demandez à Gemini d’auditer votre script : “liste tous les appels à des services externes, les scopes implicites et les lieux où une validation d’entrée manque.”

Documentation et commentaires générés

Faites écrire à Gemini des docstrings JSDoc cohérents et un README concis avec prérequis, limites, et procédures de reprise. La documentation évite le “bus factor”.

Prompt type :

“Ajoute des JSDoc à toutes les fonctions, décris les paramètres, les valeurs de retour et les erreurs possibles. Génère ensuite un README avec prérequis, installation, exécution, limites et check-list de dépannage.”

Intégration continue locale avec Clasp

Si vous sortez du simple “script lié à un fichier”, basculez sur Clasp pour versionner votre code. Demandez à Gemini un guide court : initialisation, push/pull, gestion des versions, et organisation en modules.

Exemple complet : nettoyer des emails et enrichir un score

Voici un mini-flux assemblé, prêt à adapter :

function run() {
  const { header, rows } = readRange_('Leads');     // I/O groupée
  const cleaned = transform_( [header, ...rows] );  // logique pure
  writeMatrix_('Scores', cleaned);                  // I/O groupée
}

function transform_(matrix) {
  const [header, ...rows] = matrix;
  const out = [['email','domaine','score']];
  for (const r of rows) {
    const email = String(r[0] || '').trim().toLowerCase();
    if (!validEmail_(email)) continue;
    const domaine = email.split('@')[1];
    const score = cached_(`score:${domaine}`, 3600, () => scoreFromDomain_(domaine));
    out.push([email, domaine, score]);
  }
  return out;
}

function validEmail_(s) { return /.+@.+\..+/.test(s); }

function scoreFromDomain_(d) {
  if (!d) return 0;
  if (d.endsWith('.edu')) return 90;
  if (/(gmail|yahoo|outlook)\./.test(d)) return 10;
  return 50;
}

// Utilitaires I/O et cache déjà vus plus haut : readRange_, writeMatrix_, cached_

Demandez à Gemini d’ajouter des tests, des statistiques (nb de lignes ignorées, taux d’emails invalides), et une alerte si la proportion d’erreurs dépasse un seuil.

Méthode d’amélioration continue

Adoptez un rituel hebdomadaire : mesurez le temps d’exécution moyen, les erreurs, le volume traité, et le taux de reprises. Demandez à Gemini des pistes ciblées : “réduis la complexité cyclomatique”, “remplace cette boucle par une opération vectorisée sur le tableau”, “élimine les conversions inutiles”.

Prompts utiles à copier-coller

  • “Optimise ce script pour qu’il n’ait plus aucun appel aux services Google dans des boucles.”

  • “Explique en 5 points pourquoi ce code est lent et propose un patch minimal.”

  • “Ajoute des JSDoc, des validations d’entrées et un mécanisme de cache pour la fonction lookupDomain.”

  • “Refactorise en fonctions pures testables et écris un harnais de test test_*().”

  • “Ajoute un traitement par lots de 1 000 lignes avec persistance de l’offset via PropertiesService.”

Découvrir notre offre de formations
Découvrir notre offre de formations