Blogue
Savoir-faire et technologie
Histoires, idées et perspectives sur la stratégie, la technologie et les solutions d’affaires.

Articles à la une

Nouvelles
5 min de lecture
Annonce : Spiria est certifiée SOC 2 Type 2
<h2>Qu'est-ce que la certification SOC 2 ?</h2><p>La certification SOC 2 (Service Organization Control 2) est une norme élaborée par l'American Institute of Certified Public Accountants (AICPA) qui évalue la capacité d'une organisation à gérer les risques liés à la sécurité, à la disponibilité, à l'intégrité du traitement, à la confidentialité et à la protection de la vie privée des données qu'elle traite pour le compte de ses clients.</p><p>La certification SOC 2 repose sur cinq principes, appelés critères de confiance, qui définissent les exigences minimales que doit respecter une organisation pour assurer la sécurité et la qualité de ses services. Ces critères sont les suivants :</p><ul> <li><strong>Sécurité</strong> : l'organisation protège les données contre les accès non autorisés, les modifications, les divulgations, les dommages ou la perte.</li> <li><strong>Disponibilité</strong> : l'organisation assure la disponibilité et le fonctionnement continu de ses services conformément aux accords conclus avec ses clients.</li> <li><strong>Intégrité du traitement</strong> : l'organisation traite les données de manière complète, valide, exacte, opportune et autorisée.</li> <li><strong>Confidentialité</strong> : l'organisation respecte les engagements et les obligations de confidentialité envers ses clients et les tiers concernant les données qu'elle traite.</li> <li><strong>Protection de la vie privée</strong> : l'organisation respecte les principes de protection de la vie privée définis par l'AICPA et les lois applicables en matière de collecte, d'utilisation, de conservation, de divulgation et d'élimination des données personnelles.</li></ul><p>« Obtenir et maintenir la certification SOC 2, je le vois comme un ultramarathon et non un sprint sur 100 mètres. C'est une première étape, dans un long processus en constante évolution. La cybersécurité, dans son ensemble, nécessite une rigueur et une attention aux détails constante auquel notre équipe est prête à s’attarder. »</p><p>– Vincent Huard, Vice-Président, gestion et analyse des données</p><p>Pour obtenir la certification SOC 2, une organisation doit faire l'objet d'un audit indépendant réalisé par un cabinet comptable qualifié qui vérifie qu’elle respecte les critères de confiance applicables à ses services. L'audit porte sur la conception et l'efficacité des contrôles mis en place par l'organisation pour assurer la conformité aux critères de confiance.</p><h2>Quelle est la différence entre la certification SOC 2 Type 1 et Type 2 ?</h2><p>Il existe deux types de certification SOC 2. C’est entre autres la durée de l’audit qui les distingue. SOC 2 Type 2 est couvert par l’audit le plus long et rigoureux.</p><ul> <li>La certification SOC 2 Type 1 atteste que l'organisation respecte les critères de confiance à une date donnée à une date précise. Elle évalue la conception des contrôles, mais pas leur efficacité dans le temps.</li> <li>La certification SOC 2 Type 2 atteste que l'organisation respecte les critères de confiance sur une période de temps définie, généralement de trois à douze mois. Elle évalue la conception, mais également l'efficacité des contrôles, en tenant compte de leur fonctionnement réel et de leur évolution.</li></ul><p>En d’autres mots, la certification SOC 2 Type 2 répond à des critères plus exigeants et rigoureux, car elle implique un suivi continu et une vérification régulière des contrôles. Elle offre une assurance plus élevée sur la qualité et la sécurité des services fournis par l'organisation.</p><h2>Quels sont les bénéfices pour nos clients ?</h2><p>En obtenant la certification SOC 2 Type 2, Spiria réaffirme sa posture de partenaire de confiance dans la réalisation de projets de développement de solutions numériques pour ses clients. Voici quelques bénéfices principaux qui permettent à nos clients de se lancer la tête tranquille dans des projets d’envergure avec Spiria :</p><ul> <li>La garantie que nous respectons les normes les plus élevées en matière de sécurité de l'information</li> <li>La garantie que nous protégeons les données de nos clients contre les menaces internes et externes.</li> <li>La confiance que nous assurons la disponibilité et la performance de nos services</li> <li>La confiance que nous sommes capables de réagir rapidement et efficacement en cas d'incident.</li> <li>La certitude que nous traitons vos données avec intégrité, en respectant les règles de validation, d'exactitude, de traçabilité et d'autorisation.</li> <li>La tranquillité d'esprit que nous respectons vos obligations de confidentialité et que nous ne divulguons pas vos données à des tiers non autorisés.</li> <li>La sécurité que nous respectons les principes de protection de la vie privée et que nous nous conformons aux lois applicables en matière de données personnelles.</li></ul><p>La certification SOC 2 Type 2 est un gage de confiance et de sécurité pour nos clients qui témoigne de notre engagement à fournir des services de qualité et à respecter les meilleures pratiques du secteur. Elle représente l’excellence en matière de sécurité des données dans le marché tout en étant de plus en plus prisée pour les projets de développement logiciels. Il était donc tout naturel pour Spiria d’être parmi les quelques firmes d’experts à s’y conformer en Amérique du Nord. Nous sommes fiers d’arborer cette certification et d'assurer à la fois l'excellence, la fiabilité et la rigueur de nos pratiques d’affaires.</p><p>Démarrez un projet en toute confiance : <a href="mailto:nouveauprojet@spiria.com">nouveauprojet@spiria.com</a>.</p>

Stratégie
5 min de lecture
Temps et matériel ou forfaitaire, que choisir ?
<p>Les équipes de Spiria ont une longue et riche expérience avec les deux types de contrats, et nous vous dévoilons ici ce que nous avons appris au fil du temps sur le sujet et quels sont les critères de succès pour chaque option.</p><p>Clarifions tout d’abord ce que sont ces deux types de projets :</p><h3>Projets temps & matériel</h3><p>Projets dont la portée (activités, livrables, inclusions comme exclusions, etc.) peut être plus ou moins clairement définie. L’évaluation initiale des coûts présente une fourchette de prix probable pour la réalisation du dit projet. Les coûts sont facturés selon les heures réelles exécutées et le matériel/ressources (autres coûts, par exemple des licences logicielles ou des services infonuagiques) nécessaire. Cette approche est plus flexible, car elle permet des changements de spécifications tout au long du processus de développement. L’agilité est encouragée et les contrôles de gestion de projets sont mis de l’avant.</p><h3>Projets forfaitaires ou fixes</h3><p>Projets dont la portée est plus souvent bien ou très bien définie. Le niveau de confiance de l’évaluation initiale des coûts repose sur des informations plus claires que le précédent type de projet. Comme son nom l’indique, les coûts sont fixés au départ, peu importe les heures réellement exécutées et le coût en matériel et ressources. Par conséquent, les notions de risques et de profitabilité sont des considérations plus critiques à évaluer dans ce type de projet. Toute modification des spécifications est encadrée par un processus de demande de changement et est facturée en tant que travail supplémentaire.</p><p>Dans un premier scénario, pour un projet préalablement qualifié, le type de projet (temps/matériel vs fixe) peut être imposé par le client, les exigences internes des organisations ou encore des réglementations, par exemple dans le cas des appels d’offres (majoritairement fixes). Lorsque possible, Spiria peut proposer une approche pour mitiger les risques et mieux saisir la portée du projet, comme proposer au client un investissement initial dans une phase découverte, en mode temps/matériel ou forfaitaire, dans l’intention de pouvoir proposer par la suite les phases de développement et de déploiement en mode forfaitaire. Ceci n’empêche bien sûr pas le client de changer de priorité ou de modifier la portée à la suite de la phase de découverte. Notre flexibilité doit nous permettre de négocier avec le client la portée définie en variant les inclusions/exclusions, dans l’objectif de rester dans l’enveloppe budgétaire forfaitaire contractuelle entendue.</p><p style="text-align: center;"><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/11800/process-fr.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/11800/process-fr.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/11800/process-fr.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/11800/process-fr.webp" style="width: 60%; border: none;" alt="Un cycle projet type." title="Un cycle projet type."></source></source></source></picture></p><p style="text-align: center; font-style: italic;">Figure 1. Un cycle projet type.</p><p>Dans un deuxième scénario, si le type de projet n’est pas imposé, ceci nous donne la latitude du choix de la stratégie. Habituellement, les clients prévoient des sessions de rencontres avec les différents fournisseurs pour répondre à leurs questions. Une réflexion interne s’impose ensuite pour bien évaluer les facteurs décisionnels menant à la meilleure stratégie. À cet effet, le tableau ci-dessous présente une liste non exhaustive de points qui éclairent les équipes dans cette réflexion. Ces points sont pondérables (facilement identifiables, quantifiables ou mesurables) ou impondérables, en fonction des informations fournies lors des rencontres initiales, dans les cahiers de charge, ou pouvant être obtenues par des demandes au client. Les annotations des deux colonnes de droite sont simplement des suggestions de poids relatifs aux deux types de projets.</p><table cellpadding="0" cellspacing="0" style="width:100%"> <tbody> <tr> <td style="width:76%"><strong>Points</strong></td> <td style="width:12%"><strong>Fixe</strong></td> <td style="width:12%"><strong>T&M</strong></td> </tr> <tr> <td>Le plan d’affaires, les requis, les besoins et les attentes sont claires.</td> <td>➕➕</td> <td>➕</td> </tr> <tr> <td>Les processus et règles d’affaires sont nombreux et complexes.</td> <td>➕</td> <td>➕➕</td> </tr> <tr> <td>Le budget client est identifié et la planification budgétaire est cadrée.</td> <td>➕</td> <td>➖</td> </tr> <tr> <td>L’échéancier est strict ou critique en raison du contexte client ou d’affaires.</td> <td>➕</td> <td>➖</td> </tr> <tr> <td>Les expertises nécessaires sont identifiables.</td> <td>➕</td> <td>➕</td> </tr> <tr> <td>La structure organisationnelle et décisionnelle est grande et complexe.</td> <td>➖</td> <td>➕</td> </tr> <tr> <td>Les aspects légaux sont complexes.</td> <td>➖</td> <td>➕</td> </tr> <tr> <td>Les relations sont déjà établies (historique) ou des contacts sont nos promoteurs.</td> <td>➕</td> <td>➕</td> </tr> <tr> <td>Le calcul de risques, les incertitudes et la contingence sont élevés.</td> <td>➖</td> <td>➕</td> </tr> <tr> <td>Les risques de dérives sont probables.</td> <td>➖</td> <td>➕</td> </tr> <tr> <td>Le client détient une capacité en effectifs ou en connaissances internes<br> (designer, équipe de développement, AQ, etc.).</td> <td>➕</td> <td>➕</td> </tr> <tr> <td>L’environnement technologique est connu.</td> <td>➕</td> <td>➕</td> </tr> <tr> <td>Les contraintes technologiques sont importantes (ex. : système hérité).</td> <td>➖</td> <td>➕</td> </tr> <tr> <td>Les défis d’intégration sont nombreux et complexes.</td> <td>➖</td> <td>➕</td> </tr> <tr> <td>Les choix technologiques sont imposés.</td> <td>➕</td> <td>➕</td> </tr> <tr> <td>Les données sont disponibles pour faire l’assurance qualité fidèlement.</td> <td>➕</td> <td>➕</td> </tr> <tr> <td>La solution est assujettie à des certifications spéciales.</td> <td>➖</td> <td>➕</td> </tr> </tbody></table><p><br>Le résultat de cette réflexion peut amener vers différentes approches représentées dans le diagramme suivant :</p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/11800/strategies-fr.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/11800/strategies-fr.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/11800/strategies-fr.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/11800/strategies-fr.png" style="width: 100%; border-style:solid; border-width:1px;" alt="Les différentes stratégies (approches)." title="Les différentes stratégies (approches)."></source></source></source></picture></p><p style="text-align: center; font-style: italic;">Figure 2. Les différentes stratégies. (Cliquer pour agrandir.)</p><p>La stratégie sélectionnée dicte la façon donc les ententes contractuelles sont conclues. Ce choix d’approche a des incidences sur tout le déroulement du projet et son succès final. La transparence du processus de choix et la justification des motifs auprès du client permettent de démarrer la relation sur des bases saines. Les objectifs ultimes sont de livrer un projet qui respecte nos valeurs spiriennes et qui apporte la valeur attendue au client.</p>
Tous les articles
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Culture
5 min de lecture
Le quotidien d’un développeur de logiciels
<p>Tous ces systèmes ont d’abord dû être imaginés et développés, puis il faut les maintenir tout au long de leur vie utile. Tous les jours, nous les utilisons quotidiennement sans même plus y penser. Mais savez-vous en quoi consiste le travail quotidien des programmeurs qui ont développé tous ces outils dont on ne saurait plus se passer ?</p><p>En tant que développeur spécialisé en applications web, je vous propose un aperçu des tâches et défis que je rencontre typiquement chaque jour. Bien sûr, chaque projet de <a href="https://www.spiria.com/fr/services/developpement-axe-performance/developpement-logiciel-sur-mesure/">développement logiciel</a> est unique et chaque équipe a sa façon de faire, mais cette vue d’ensemble est sans doute assez représentative de l’approche générale pour tout type de développement logiciel.</p><p>Notons d’abord que malgré le terme courant de “développement” qui recouvre tout ce qui participe à la naissance d’un logiciel, le développement logiciel n’est pas l’affaire uniquement des développeurs. En fait, il fait appel à différents professionnels et à de nombreuses compétences autres que la seule écriture de code.</p><h2>Le cycle de développement logiciel</h2><p>Dans le cycle de développement logiciel moderne dit “Agile”, une application est continuellement en développement :</p><p><img src="https://mirror.spiria.com/site/assets/files/4639/cycle_developpement.png" style="width: 50%; border: none;" alt="Development cycle." title="Development cycle."></p><ol> <li><b>Analyse</b> — L’analyse des besoins : nouvelles fonctionnalités, bogues à corriger, etc.</li> <li><b>Conception</b> — Élaboration des maquettes, de l’architecture logicielle requise, etc.</li> <li><b>Implémentation</b> — Développement (“codage”).</li> <li><b>Tests</b> — Assurance qualité (AQ) pour valider le bon bon fonctionnement et trouver les bogues manqués lors du développement.</li> <li><b>Déploiement</b> — Mise en production.</li></ol><p>Les meilleures pratiques veulent que le développement passe par toutes les étapes de ce cycle à intervalles réguliers, de manière à avoir des mises à jour fréquentes en production. En général, un cycle typique, appelé “sprint”, dure d’une à quatre semaines selon la nature du projet, mais dans les cas d’urgences majeures (par exemple, un “hotfix”), un cycle complet peut être accompli en aussi peu qu’une seule journée.</p><p>Il est à noter que tous les cycles ne produisent pas nécessairement de changements visibles pour les utilisateurs finaux de l’application. Un cycle peut en effet contenir uniquement de l’analyse ou des changements d’architecture en arrière plan, en préparation de fonctionnalités futures ou pour stabiliser la plateforme. De plus, une fonctionnalité peut être divisée en plusieurs petites tâches moins complexes afin de mieux répartir le travail entre les différents développeurs.</p><p>À l’occasion et selon la répartition des équipes au sein d’une entreprise, le développeur est amené à devoir réaliser des tâches relevant de chaque étape du cycle. Un bon développeur doit donc être polyvalent et pouvoir s’adapter rapidement lorsque nécessaire.</p><p>Ainsi, même si on a la plupart du temps une équipe d’<a href="https://www.spiria.com/fr/services/developpement-axe-performance/assurance-qualite-test-automatises/">assurance qualité</a> (AQ) dédiée pour tester l’application et trouver les bogues avant la mise en production des nouvelles fonctionnalités, un développeur effectue tout de même certains tests lors de l’implémentation afin de corriger une partie des bogues en amont.</p><p>Mentionnons que les phases du cycle de développement ne sont pas nécessairement séquentielles. Par exemple, les phases d’analyse et de conception du prochain cycle peuvent être accomplies en parallèle durant le cycle en cours.</p><p>La phase d’analyse s’accompagne généralement des tâches suivantes :</p><ol> <li>Analyse des besoins : identification et priorisation des bogues et des nouvelles fonctionnalités pour le prochain cycle.</li> <li>Documentation des besoins techniques à implémenter pour répondre aux besoins identifiés. Division des fonctionnalités complexes en sous-tâches plus simples.</li> <li>Estimation de la complexité et du temps requis pour chacune des tâches déterminées.</li> <li>Planification et validation du contenu du prochain cycle de développement.</li></ol><p>La phase d’analyse est amorcée en étroite collaboration avec le client (représenté par le “Product Owner”), et les équipes de développement et d’assurance qualité sont généralement impliquées lors des phases finales d’estimation et de planification.</p><h2>Le travail du codeur</h2><p>Pour ce qui est du développement à proprement parler, un développeur réalise généralement les travaux suivants pour chaque tâche :</p><ol> <li>Implémentation de la tâche dans le code (ajout de la fonctionnalité dans le code ou ajustement du code existant pour corriger un bogue) : <ul> <li>Recherche et documentation (utiliser une librairie logicielle externe, trouver une solution existante pour résoudre un bogue, explorer des alternatives technologiques, etc.).</li> <li>Ajout de <a href="https://fr.wikipedia.org/wiki/Test_unitaire">tests unitaires</a> ou même de tests fonctionnels et/ou de tests d’intégration selon le projet.</li> <li>Test de la fonctionnalité dans un environnement de développement dédié.</li> </ul> </li> <li>Ouverture de la <a href="https://fr.wikipedia.org/wiki/Revue_de_code">revue de code</a> aux autres développeurs : <ul> <li>Ajustements et corrections suite aux retours de la revue de code (le cas échéant).</li> </ul> </li> <li>Déploiement de la fonctionnalité dans l’environnement d’AQ dédié : <ul> <li>Ajustements et corrections des bogues trouvés par l’équipe d’assurance qualité (s’il y a lieu).</li> </ul> </li></ol><p>Une fois toutes les tâches complétées et mises ensemble, on peut alors faire le déploiement du “sprint” achevé en production.</p><p>Notons finalement que toutes les étapes du cycle de développement ne sont pas indépendantes, mais bien interreliées.</p><p>Par exemple, après l’implémentation d’une fonctionnalité, si des bogues sont détectés par l’équipe d’assurance qualité, le développeur responsable de la tâche va les corriger en retournant à l’étape d’implémentation.</p><p>Ou bien encore, si un bogue est détecté en production durant un cycle, il est alors analysé et priorisé. Selon sa gravité, il sera soit corrigé en “hotfix”, soit inséré au cycle actuel (possiblement à la place d’une autre fonctionnalité) en vue du prochain déploiement, soit reporté à un cycle ultérieur.</p><h2>Collaborer et communiquer</h2><p>La collaboration et la communication entre les différentes équipes sont l’une des principales clés pour le développement efficace d’une application de qualité. Un développeur est donc en constante communication avec les autres développeurs et membres de l’équipe selon l’état d’avancement du cycle.</p><p>Idéalement, les communications se font directement en personne, mais selon la taille des entreprises et l’emplacement des clients, il peut arriver que les équipes soient réparties entre plusieurs villes, pays ou même continents. Il arrive donc que des réunions ou discussions soient réalisées de manière virtuelle, mais elles n’en sont pas moins importantes pour autant. Notons aussi que de nos jours, plusieurs entreprises offrent également des possibilités de télétravail à leurs employés, auquel cas la qualité et la régularité des communications au sein de l’équipe sont d’autant plus essentielles.</p><p>Pour un développeur, une journée type est donc par exemple accompagnée des tâches suivantes (pas nécessairement dans cet ordre) :</p><ul> <li>Synchronisation avec le reste de l’équipe (par exemple, une rencontre “scrum”).</li> <li>Revue de code des fonctionnalités terminées par les autres développeurs.</li> <li>Ajustement des fonctionnalités terminées à la suite de la revue de code des autres développeurs ou des retours de l’équipe AQ.</li> <li>Développement de nouvelles fonctionnalités (implémentation + test).</li> <li>Participation à l’estimation des prochaines fonctionnalités (généralement une seule fois par “sprint” ou cycle selon les besoins).</li></ul><p>Bien sûr, tout ceci est très variable, selon le projet et selon le rôle de chaque développeur au sein de l’équipe.</p><p>Pour conclure, le développement logiciel reste un processus complexe et en constante effervescence. Outre les développeurs, il fait intervenir plusieurs acteurs clés tous aussi importants. Et la prochaine fois que vous utiliserez votre application préférée, peut-être aurez-vous l’occasion de penser à la somme de travail et les efforts soutenus des équipes de développement qui l’ont rendue possible.</p>

Stratégie
5 min de lecture
Comment planifier mon projet de développement logiciel pour avoir le retour sur investissement le plus rapide ?
<p>Une chose importante à considérer avant de se lancer est : <i>« que cherchez-vous vraiment à atteindre ? »</i>. Il y a une distinction entre une demande de planification et le besoin d’être rassuré — deux préoccupations tout à fait valables.</p><p>Examinons de plus près la planification du retour sur investissement le plus rapide.</p><h2>En préalable</h2><p>Les gens aiment obtenir une question en réponse à leur question (en fait, non, ce n’est pas le cas). Cependant, la première étape est de comprendre : <b>pourquoi le plus rapide</b> ?</p><p>Voici trois questions qui sont essentielles pour bien comprendre les objectifs et les préoccupations d’un client au-delà des tout premiers échanges et des trois lettres magiques (R-O-I) :</p><ul> <li>Quel est le délai acceptable pour être dans le « plus rapide » ?</li> <li>Que sacrifiez-vous pour obtenir un retour sur investissement rapide au lieu de reporter sur le moyen ou long terme ?</li> <li>Qui a décidé de l’objectif d’un retour sur investissement rapide, et cette décision remporte-t-elle l’adhésion au sein de l’entreprise ?</li></ul><p>La dernière question sert à comprendre si cet objectif est quelque chose qui aidera l’entreprise ou bien la personne qui la représente. Bien sûr, nous préférerons être dans le premier cas, mais le second est parfois un passage obligé pour faire approuver le projet.</p><h2>La seule chose qui soit constante, c’est le changement</h2><p>Bien qu’il soit louable de prévoir un retour sur investissement rapide en début de projet, nous devons déterminer quels sont les <b>facteurs de changement</b> susceptibles d’affecter à la fois la définition des termes « le plus rapide » et « retour sur investissement ». Il vaut vraiment la peine de vérifier ces facteurs auprès du client, pour voir si ces définitions sont invariables ou évolutives. Ces facteurs peuvent inclure :</p><ul> <li>Le marché</li> <li>La concurrence</li> <li>La vision de l’entreprise</li> <li>La pression en interne, les promoteurs du projet</li></ul><h2>Qualifier et quantifier</h2><p>En matière de retour sur investissement, vous devez vous éloigner du terme et de ses implications et mettre votre client potentiel au défi de définir ce qu’il signifie réellement. Comment mesurer le « retour sur investissement le plus rapide » et comment déterminer si l’objectif a été atteint ?</p><p>Tout d’abord, demandez à votre client de prévoir le <b>coût de l’inaction</b> dans les délais impartis. En d’autres termes, si le client n’allait pas de l’avant avec le projet de développement du logiciel, combien cela lui coûterait-il ? Cela peut être aussi direct que la perte de revenus, ou indirect comme l’effet sur la motivation et la performance des employés. Par exemple, les employés peuvent passer une partie importante de leur journée à effectuer des tâches qui ne tirent pas parti des compétences pour lesquelles ils ont été engagés. Cela inclut toute saisie manuelle de données qui prend du temps et qui est le préalable nécessaire pour effectuer l’analyse des données pour laquelle ils ont été engagés. Cela peut entraîner de la frustration, une baisse des performances et de la motivation, ainsi qu’une diminution du taux de rétention des employés.</p><p>Ensuite, concentrez-vous sur la dernière lettre de « ROI » : l’investissement. L’investissement peut être élevé au départ, puis diminuer progressivement au fil du temps, ou il peut être assez constant. Le client cherche-t-il à <b>récupérer son investissemen</b>t très rapidement après la mise en service, ou envisage-t-il un retour progressif par phase ou par étape ? Ces informations permettront de fixer des jalons précis pour la mesure du ROI.</p><p>Enfin, nous parlons souvent de <b>la <em>valeur</em> dans le développement logiciel</b>. Ce terme est souvent utilisé, mais il peut avoir une signification différente selon les personnes et leur fonction. L’idée qu’un développeur de logiciels se fait de la valeur d’une fonctionnalité donnée peut différer de celle que s’en font les principaux intéressés chez le client, surtout s’ils ne partagent pas les mêmes critères. Une échelle commune pour déterminer la valeur permettra à chaque membre de l’équipe de fournir la valeur nécessaire pour atteindre un bon retour sur investissement.</p><h2>Laissez les experts être des experts</h2><p>Souvent, les clients décrivent la solution qu’ils pensent pouvoir apporter au problème, au lieu de décrire le problème lui-même. Cela peut avoir l’effet négatif d’orienter votre expert vers une voie préconçue. En décrivant leur problème de manière simple et succincte, les clients ont l’avantage de laisser l’expert envisager une solution de son propre point de vue.</p><p>Il en va de même pour notre question de « retour sur investissement le plus rapide ». Nous avons parlé plus tôt de la définition et de la quantification du ROI — ce sont les lignes directrices qui encadrent l’objectif au niveau macro. Si l’objectif est correctement compris et communiqué, et s’il y a adhésion, les experts peuvent traduire l’objectif macro à un niveau micro.</p><h2>Comment planifier</h2><p>Pour faire simple, voici quelques points importants à prendre en compte lors de l’élaboration d’un plan pour un retour sur investissement rapide :</p><ol> <li>S’accorder sur la définition de « retour sur investissement le plus rapide ».</li> <li>Comprendre les raisons qui se cachent derrière.</li> <li>Fixer des objectifs quantifiables.</li> <li>Suivre et mesurer.</li> <li>Ajuster en fonction de l’évolution des facteurs.</li> <li>Communiquer.</li></ol><p>Pour parler sans détour, cela se résume à <i>« être sur la même longueur d’onde, tous ensemble »</i>. Plus facile à dire qu’à faire, car les affaires et la technologie ne font pas toujours bon ménage. Une bonne équipe — le client et son entreprise de développement — partage son expertise, maximise les forces de l’autre partenaire et minimise les faiblesses. Le « retour sur investissement » peut avoir peu de sens pour un développeur de logiciels qui, en revanche, se soucie de la valeur ; sa définition de la valeur se traduit-elle par un « retour sur investissement », et vice-versa ? Peut-être que oui, ou peut-être aurez-vous besoin de faire un travail de conciliation et de représentation des différentes perspectives pour atteindre votre objectif commun.</p>

Culture
5 min de lecture
Cinq importantes leçons apprises en tant que développeur junior
<h2>Si vous n’avez pas le temps de tout lire :</h2><p><b>Laissez votre ego à la porte</b><br>Votre ego ne fera que vous ralentir sur le chemin de votre progression en tant que programmeur. Laissez-le derrière vous.</p><p><b>Le travail en équipe est essentiel</b><br>Vous n’irez pas loin sans l’équipe. Mettez de côté vos propres intérêts et regardez les choses dans leur globalité.</p><p><b>Comprenez que chacun a des attentes différentes</b><br>Tout le monde ne travaille pas et ne pense pas comme vous. Cela ne veut pas dire qu’ils ont tort, mais simplement qu’ils ont des attentes différentes ; et il vous faut l’accepter.</p><p><b>Sortez de votre zone de confort</b><br>Évitez de vous confiner dans votre petit confort et allez explorer les vastes mondes de la technologie. Apprenez des choses sans rapport direct avec votre travail ; vous ne savez jamais quand cela vous sera utile.</p><p><b>N’allez pas jusqu’à l’épuisement</b><br>Ce n’est pas un sprint, mais un marathon. Prenez du temps pour vous et profitez de la vie en dehors du travail.</p><h2>Laissez votre ego à la porte</h2><p>La somme de connaissances requise pour mener un projet à bien est tout simplement énorme. Vous devez posséder des compétences appropriées en matière d'UX/UI, de back-end, de front-end, de base de données, de DevOps, d'architecture, de sécurité, etc. Faut-il vous immerger dans Pluralsight et essayer de tout apprendre de fond en comble ? Si vous voulez passer des années à ne rien faire d’autre, pourquoi pas… Autrement, essayez donc d’apprendre de vos pairs qui ont passé de nombreuses années à perfectionner leur savoir-faire.</p><p>Si vous avez un gros ego, non seulement vous n’allez pas écouter et apprendre, mais vos coéquipiers ne seront de toute façon pas enclins à vous transmettre des connaissances. Vous considérerez chaque correctif ou suggestion d’amélioration comme un affront personnel. Vous finirez par gaspiller beaucoup d’énergie à essayer de protéger quelque chose de peu d’utilité : votre ego.</p><p>Je n’ai pas échappé à ce piège. Je pensais tout savoir, jusqu’à ce que je réalise que… ce n’était pas le cas. Mon savoir n’était qu’une goutte d’eau dans l’océan. J’ai réalisé à quel point mon ego était grand et stupide lorsque j’ai commencé à travailler avec des gens qui étaient bien plus savants que moi. Lâcher son ego est plus facile à dire qu’à faire, et cela ne se réalise pas du jour au lendemain, mais les bénéfices en valent la peine. Je vous recommande l’ouvrage <i>Ego is the Enemy</i> de Ryan Holiday. Cet excellent livre est facile à lire, et il vous explique les raisons pour lesquelles votre ego ne vous est d’aucune utilité et pourquoi vous devriez vous en séparer.</p><h2>Le travail en équipe est essentiel</h2><p>Derrière tout excellent logiciel, il y a une équipe formidable qui l’a conçu. Je n’ai réalisé l’importance du travail d’équipe que lorsque j’ai été propulsé dans un environnement concret, avec un vrai projet et une vraie équipe. C’est une dynamique différente de celle à laquelle j’étais habitué, quand mon propre intérêt passait avant celui de l’équipe.</p><p>Communiquez souvent, posez des questions lorsque vous n’êtes pas sûr de quelque chose, signalez les problèmes dès qu’ils surviennent. Tout le monde doit faire sa part dans l’intérêt de la coordination du projet. Ne restez pas sans communiquer pendant des jours. Vos décisions doivent être prises dans l’intérêt de l’équipe et non dans votre propre intérêt, et vous devez travailler avec l’équipe et non contre elle. N’oubliez pas que personne n’apprécie un programmeur « héros » qui pense pouvoir faire le travail de tout le monde.</p><p>Je suis plutôt un loup solitaire, un penseur avant un orateur, un introverti. Pour moi, communiquer et être là pour l’équipe n’avait jamais été un problème parce que je n’en avais pas le besoin. Dans mes emplois précédents et à l’école, je pouvais simplement brancher mes écouteurs et travailler comme je voulais, au rythme que je voulais, avec les outils que je voulais. Mais j’ai fini par devoir adapter mon comportement et mes habitudes, car aussi amusante que soit la liberté totale, il faut être plus d’un pour réaliser quelque chose d’important et de significatif. Seul, on va plus vite, ensemble, on va plus loin.</p><h2>Comprenez que chacun a des attentes différentes</h2><p>Vous travaillerez avec beaucoup de gens tout au long de votre carrière. Comme chaque personne est unique, votre relation de travail avec chacune d’entre elles doit l’être également. Cela signifie que vous devez essayer de comprendre les attentes et besoins de chaque personne afin de mieux comprendre pourquoi elle pense et agit comme elle le fait.</p><p>Cela ne signifie pas que vous devez avoir un doctorat en psychologie. Lisez plutôt les <i>styles interpersonnels</i> selon Larry Wilson. Cela donne un bon aperçu du concept de « personnalités fondamentales » en termes simples. En bref, vous avez :</p><ul> <li>L’analytique : axé sur les données, il a besoin de clarté et de réponses objectives.</li> <li>Le fonceur : concentré sur un objectif, il a besoin d’avancer rapidement et efficacement.</li> <li>L’expressif : animé par le sentiment, il a besoin de liberté et de tâches stimulantes.</li> <li>L’aimable : orienté vers la socialibilité, il a besoin d’interactions et d’une atmosphère positive.</li></ul><p>Le but n’est pas d’essayer de plaire à tout le monde tout le temps, mais plutôt de faire preuve d’empathie lorsque quelqu’un ne se sent pas motivé par son travail. C’est un excellent outil pour vous aider à mieux comprendre vos coéquipiers et à adapter en conséquence votre relation de travail avec eux.</p><p>Pendant longtemps, je ne comprenais pas les gens qui avaient constamment besoin de réponses concernant leur travail. Je me disais : « Si vous ne savez pas, prenez une décision et faites avec. Cela ne doit pas être si difficile que ça ». J’ai toujours eu l’impression qu’ils avaient besoin d’être nourris à la cuillère, alors qu’en fait, ils avaient juste besoin de clarté. Ce sont des analytiques, et c’est tout simplement dans leur nature. Je travaillais plus vite qu’eux, mais mon travail devait être corrigé, tandis que le leur était approuvé à la révision. J’avais besoin de rapidité, alors qu’ils avaient besoin de clarté. Il n’y a pas de bien ou de mal, juste des besoins différents.</p><h2>Sortez de votre zone de confort</h2><p>N’ayez pas peur d’essayer quelque chose de complètement nouveau. Il y a tant de domaines, de langages, de frameworks, de méthodes de travail, d’architectures, de paradigmes différents, et la liste est longue. Même si cela n’est pas directement lié à votre métier, vous devriez explorer. Il y a de fortes chances pour que ce que vous avez appris en sortant de votre domaine profite à votre travail d’une manière ou d’une autre.</p><p>Prenez un peu de temps chaque semaine pour aller explorer, même si ce n’est que quelques heures. Il y a quelque chose d’euphorisant à apprendre par simple curiosité. Vous avez plus de temps pour analyser, questionner et creuser que quand vous devez apprendre les mêmes choses dans la précipitation pour un projet.</p><p>Aucun savoir n’est jamais gaspillé, et vous devriez profiter pleinement de votre jeunesse pour faire bon usage de tout le temps qu’il vous reste à l’horloge de la vie. Le temps est votre plus grand atout. Faites-en bon usage.</p><h2>N’allez pas jusqu’à l’épuisement</h2><p>Il est tout à fait naturel, au début, de vouloir faire ses preuves en travaillant comme un fou. Vous êtes jeune, vous commencez votre carrière et vous voulez que tout le monde sache que vous ne serez pas un poids mort. Mais combien de temps pouvez-vous tenir le rythme avant de tomber en panne de carburant ? Quelques mois si vous êtes chanceux ? Et vous ressentirez les mêmes choses qu’après une chute de glycémie : manque de motivation et de concentration.</p><p>Si vous recherchez le respect, ce n’est pas la façon de le gagner. Les travailleurs plus âgés ont du vécu et savent que votre folle accumulation de “story points” ne durera pas. Ne gaspillez pas votre énergie en début de course ; gardez-la pour quand vous en aurez vraiment besoin. Il y aura des moments où vous aurez besoin de doubler la mise, et ce sera un cauchemar si vous avez consommé tout votre carburant.</p><p>Je suis coupable d’avoir cédé à ce comportement. Je pensais que plus je publierais de “user stories”, plus je deviendrais utile. J’ai essayé d’être le héros que personne n’avait demandé. Ce fut de courte durée. Au début, je me sentais bien. J’ai reçu quelques tapes dans le dos, quelques mentions dans des réunions. Et puis les mois ont passé. Ma motivation s’est effondrée. J’avais peu de patience et moins de concentration : une combinaison mortelle. Tout ce que je voulais alors, c’était juste m’arrêter un moment, mais ce n’était pas possible. Je devais prendre de nombreuses pauses au cours de la journée pour rester lucide, garder mon esprit clair.</p><p>Morale de l’histoire : prenez du temps pour vous, faites de l’exercice, reprenez les passe-temps que vous avez mis de côté parce que vous étiez trop occupé par votre emploi du temps de fou. Voyagez et lisez. Être heureux en dehors du travail est la meilleure façon d’être heureux au travail.</p>

Coin des développeurs
5 min de lecture
Jouer au golf avec Dict
<p>La question que nous allons explorer est la suivante : <i><b>quelle est la vitesse d’accès maximale à un dictionnaire ?</b></i></p><p>Oui, c’est un peu bizarre comme code golf, mais soyez patient. Vous verrez, on va arriver quelque part d’intéressant. Pas nécessairement l’endroit où vous aviez prévu d’aller… mais nous y arriverons ensemble, en équipe ! Non, je plaisante. Pas besoin de travailler en équipe. Je ferai tout le travail et vous pourrez vous asseoir et me regarder.</p><p>L’ensemble du code dont nous allons parler est <a href="https://github.com/pierrebai/FastDict">disponible sur GitHub</a>.</p><p>(Notez qu’il y a plusieurs branches, “master” pour le point de départ, “fast-dict” pour le résultat final).</p><h2>Les règles</h2><p>Comme vous le verrez à la fin, les lois de l’univers seront bafouées. Mais cela ne veut pas dire que nous ne pouvons pas inventer nos propres lois. C’est pourquoi je vais établir des règles, la forme de base de ce à quoi le dictionnaire doit ressembler et la fonctionnalité qu’il fournira.</p><p>Je commencerai par donner une description générale de la fonctionnalité, puis je fournirai une brève déclaration en C++ de l’interface. Pour une vue complète de l’API C++, reportez-vous à la branche “master” sur GitHub. Passons maintenant à la description !</p><h3>Description de haut niveau</h3><table style="width:100%"> <tbody> <tr> <th>Classe C++</th> <th>But</th> <th>API</th> </tr> <tr> <td style="vertical-align: top;"><code>element</code></td> <td style="vertical-align: top;">L’élément du dictionnaire. Contient une valeur de n’importe quel type. Par exemple : un entier, un double, du texte ou un autre dictionnaire.</td> <td style="vertical-align: top;">Définir des valeurs, lire la valeur, réinitialiser l’élément, comparer des éléments, etc.</td> </tr> <tr> <td style="vertical-align: top;"><code>name</code></td> <td style="vertical-align: top;">Une étiquette utilisé pour accéder aux éléments du dictionnaire.</td> <td style="vertical-align: top;">Construire de nouveaux noms, comparer les noms.</td> </tr> <tr> <td style="vertical-align: top;"><code>dict</code></td> <td style="vertical-align: top;">Le dictionnaire, indexé par noms, contenant des éléments.</td> <td style="vertical-align: top;">Construction, ajout, suppression et accès.</td> </tr> </tbody></table><h3>Code C++</h3><p>Je ne donnerai qu’une courte description. Vous pouvez consulter le code sur GitHub pour les détails. Le point principal qui nous intéresse est l’accès au dictionnaire, c’est donc tout ce que je vais montrer :</p><pre><code> // Element retrieval. element & operator [](const name &); const element & operator [](const name &) const;</code></pre><p>Très simple, très standard. La fonction d’accès reçoit un <code>nom</code> et renvoie un <code>élément</code>. Pour aider à comprendre ce que sont les noms, voyons comment ils sont créés :</p><pre><code> // You need to derive from name to create a concrete name. // All instances of a given concrete name are equal. struct name { // Invalid-name, default constructor. name() : _name(nullptr) {} protected: // The text passed for the name by its sub-classes must be static // so that each address is unique. name(strptr n) : _name(n) {} };</code></pre><p>Alors que le <code>nom</code> a un constructeur public par défaut, son autre constructeur est protégé. Pourquoi ? Vous verrez la raison profonde plus loin… mais cela signifie donc que toutes les instances doivent provenir de sous-classes ? Oui ! Chaque <code>nom</code> sera une instance d’une sous-classe de <code>nom</code> ! Mais quelle sous-classe ? Eh bien… <b>toutes</b>, bien sûr !</p><p>En fait, si vous regardez dans le repo GitHub, vous verrez que je fournis un en-tête <code>voc.h</code>. Cet en-tête déclare… un vocabulaire de noms. Comme il a été suggéré plus tôt, chaque <code>nom</code> réel est une sous-classe… une sous-classe différente pour chaque <code>nom</code> distinct ! Le fichier se présente comme ceci :</p><pre><code> namespace voc { #define MAKE_NAME(n) struct n ## _n : dak::name { n ## _n() : name(L ## #n) {} }; MAKE_NAME(apple); MAKE_NAME(person); // etc… const apple_n apple; const person_n person; }</code></pre><p>La classe d’<code>éléments</code> elle-même est une classe simple qui peut contenir une valeur de n’importe quel type commun. Elle n’a rien de particulier. Il serait bon que vous réfléchissiez à la vitesse à laquelle vous pourriez réaliser une telle interface de dictionnaire. Vous pouvez prendre comme point de départ la branche “master” de GitHub. S’agira-t-il de N log N ? N ?, log N ? Temps constant ? Plus rapide ? Attendez, plus rapide que le temps constant ? Qu’est-ce que cela signifierait ?</p><h2>Les plis</h2><p>Maintenant que nous avons établi les règles, il est temps de les plier à notre avantage. Bien sûr, comme avec tout bon arnaqueur, les règles ont été soigneusement pensées pour donner l’avantage à la maison.</p><p>Il y a notamment une bonne raison derrière la conception de la classe de <code>noms</code>. Vous voyez, le fait d’avoir différents types pour différents noms nous permet de subvertir le système de types C++ à notre avantage. En particulier… nous pouvons subvertir le mécanisme de surcharge des fonctions !</p><p>Souvenez-vous des fonctions d’accès aux <code>éléments</code> ? Que se passerait-il s’ils étaient surchargés ?</p><pre><code> // Element retrieval. element & operator [](const name &); const element & operator [](const name &) const; // Overload!!! inline element& operator [](const voc::rock_n&) inline const element& operator [](const voc::rock_n&) const</code></pre><p>Cela signifie que nous pouvons retourner l’<code>élément</code> sans avoir à le chercher ! Une tricherie totale ! Mais comment retrouver l’élément si le <code>voc::rock</code> est accessible par la version prenant un <code>nom</code> simple et non un <code>voc::rock</code> ? Comment les éléments du <code>dict</code> pourraient-ils être trouvés lors d’une itération normale ? Facile ! Nous créons des éléments proxy dans la <code>map</code> du dictionnaire, chaque proxy reporte tout son comportement sur la copie à accès direct. En gros, nous ajoutons quelques fonctions à la classe d’éléments pour enregistrer s’il s’agit d’un proxy. Nous ajoutons également une fonction à la classe <code>dict</code> pour enregistrer chaque <code>élément</code> proxy et l’<code>élément</code> d’accès direct auquel il se réfère.</p><pre><code> struct dict { protected: std::map<name element=""> _elements; // Sub-classes call this during construction // to add the permanent proxy elements. void add_permanent_proxy(const name& n, element &); }; struct element { bool is_proxy() const; bool is_permanent() const; };</name></code></pre><p>Le résultat est que nous pouvons accéder aux éléments de notre choix au moment de la compilation ! Il suffit de sous-classer la classe <code>dict</code> et d’ajouter les éléments proxy qui seront accessibles sous les noms de votre choix. La classe résultante agit comme un <code>dict</code>, et peut être utilisée partout où un <code>dict</code> peut se trouver, mais si vous connaissez le véritable type de <code>dict</code> et le véritable nom auquel vous voulez accéder, vous obtenez un accès à la compilation grâce à l’inlining et à la surcharge des fonctions.</p><h2>La torsion</h2><p>Dans le domaine de la folie, nous ne nous satisferions pas de cette médiocre ruse. Cette subversion ne va pas assez loin. Nous voulons plus de vitesse ! Nous avons un accès en temps réel à notre élément, mais nous voulons un accès en temps réel à la <b>valeur</b> contenue dans l’élément. Est-ce même possible ? Mais oui, c’est possible !</p><p>Le tour de passe-passe que nous utiliserons consiste à sous-classer la classe d’<code>éléments</code>, où réside la valeur. Si nous connaissons à l’avance le type de la valeur que nous voulons conserver sous un <code>nom</code>, nous pouvons l’obliger à toujours avoir ce type, à être connu au moment de la compilation. Connaître le type de la valeur que nous voulons conserver sous un <code>nom</code> spécifique n’est pas inhabituel, c’est même typique ! C’est ainsi que nous concevons les classes, les schémas et les bases de données après tout.</p><p>Voici donc un exemple typique de cette sous-classification. (Voir la branche “fast-dict” sur GitHub pour toutes les variations fournies) :</p><pre><code> struct eint64 : element { operator int64&() { return _i; } // etc... };</code></pre><p>Comme on peut le voir, elle peut <code>inliner</code> l’accès à la valeur réelle contenue dans l’<code>élément</code>. Notre sous-classe <code>dict</code> peut maintenant renvoyer un tel <code>eint64</code> dans sa fonction surchargée d’accès à l’<code>élément</code>, et offrir un accès complet à la valeur directe en temps de compilation ! Comme ceci :</p><pre><code> inline eint64& operator [](const voc::rock_n&) { return _rock; } inline const eint64& operator [](const voc::rock_n&) const { return _rock; }</code></pre><p>Pour supporter les sous-classes de l’élément, une fonction supplémentaire est ajoutée à l’<code>élément</code> pour lui faire savoir que le type de <code>valeur</code> est désormais fixe :</p><pre><code> bool is_fixed() const { return _fixed == fixedtype::fixed; }</code></pre><h2>La preuve</h2><p>Mais je ne me contente pas de prétendre qu’il s’agit d’un accès en temps de compilation, je le prouve ! Pas seulement le prouver, mais le comparer à un accès à une structure pure. C’est exact ! Alors que la sous-classe du dictionnaire avec ses fonctions surchargées peut être utilisée comme un <code>dict</code> normal, et que tous ses éléments, y compris les éléments permanents, proxy, typés peuvent être trouvés par recherche normale ou par itération, elle est tout aussi rapide qu’une <b>structure brute</b> ! Tout aussi rapide que ceci :</p><pre><code> struct rock_struct { int64 rock = 42; };</code></pre><p>Dans la branche “fast-dict”, il existe des tests unitaires, et parmi eux deux tests fictifs qui ont été utilisés uniquement pour comparer la génération du code du sous-dict et de la structure. J’ai capturé le code assembleur des deux, et voici le résultat et comme nous l’avons prétendu, chacun est aussi rapide que l’autre !</p><pre><code> d1.rock = rand();call qword ptr [rand] movsxd rcx,eax mov qword ptr [rsp+38h],rcx use_rock(d1);lea rcx,[d1] call dak::use_rock std::wcout << d1.rock;mov rbx,qword ptr [d1] mov rcx,qword ptr [std::wcout] mov rdx,rbx call qword ptr [operator<<] d1.rock += rand();call qword ptr [rand] movsxd rcx,eax add rbx,rcx use_rock(d1);lea rcx,[d1] mov qword ptr [d1],rbx call dak::use_rock std::wcout << d1.rock;mov rdx,qword ptr [d1] mov rcx,qword ptr [std::wcout] call qword ptr [operator<<] use_rock(d1);lea rcx,[d1] call dak::use_rock</code></pre><pre><code> d1[voc::rock] = rand();call qword ptr [rand] movsxd rcx,eax mov qword ptr [rsp+38h],rcx use_rock(d1);lea rcx,[d1] call dak::use_rock std::wcout << d1[voc::rock];lea rdx,[rsp+38h] mov rcx,qword ptr [std::wcout] call dak::operator<< d1[voc::rock] += rand();call qword ptr [rand] add eax,dword ptr [rsp+38h] movsxd rcx,eax mov qword ptr [rsp+38h],rcx use_rock(d1);lea rcx,[d1] call dak::use_rock std::wcout << d1[voc::rock];lea rdx,[rsp+38h] mov rcx,qword ptr [std::wcout] call dak::operator<< use_rock(d1);lea rcx,[d1] call dak::use_rock</code></pre><h2>Conclusion</h2><p>Nous nous sommes mis en route sur le terrain de golf, en explorant l’accès au dictionnaire et en essayant de voir jusqu’où nous pourrions descendre sur le parcours. Et là, nous sommes allés très bas !</p><p>Mais je vous sens tendu, confus et choqué.</p><p>C’est une parodie de design, une abomination ! Dériver d’une classe <code>dict</code> ? Dériveriez-vous d’un <code>std::vector</code>, d’une <code>std::map</code>, d’une <code>std::pair</code> ? Quel genre de programmeur respectable ferait cela ? Et je serais d’accord ! (Attendez, quoi ? Qui a dit ça ?) Non, non, non, non, je serais vraiment d’accord ! Je le serais, je le serais, je le serais, sauf que…</p><p>… voyez-vous, tout dans la vie est une question de perspective. Tout tient dans la façon de percevoir le monde. Et dans la programmation, la perception est souvent une question de noms. Les noms de types, les noms de fonctions, les noms de variables. Qu’est donc qu’un nom ? Les noms façonnent notre vision du monde et, à une échelle plus humble, nos designs. Alors… et si je vous disais que <code>dict</code> n’est pas le vrai nom de la classe ? Que se passerait-il si nous le renommions… <code>objet</code> ?</p><p>Ah, l’illumination finale ! Oui, maintenant il est logique de dériver d’<code>objet</code>. Maintenant, il est logique que nous ajoutions des éléments permanents fixes à un <code>objet</code> pour qu’il contienne des valeurs de type fixe ! Ce n’est même plus un design surprenant. C’est essentiellement la façon dont un langage comme Python fonctionne sous les couvertures. En Python, chaque objet de chaque classe n’est en fait qu’un dictionnaire de valeurs indexées par des noms. Et maintenant, vous pouvez le faire directement en C++.</p><p>C’est aussi très utile. Vous n’avez plus besoin d’écrire et de réécrire du code passe-partout pour chaque <code>structure</code> et chaque <code>classe</code>. Vous pouvez avoir une seule implémentation pour tous les types, pour des choses comme la sérialisation, l’annulation/rétablissement, la recherche de données, la connexion à des éléments de l’interface utilisateur et diverses autres activités que vous pouvez sûrement imaginer. Vous l’écrivez une fois pour la classe <del><code>objet</code></del> <code>dict</code>. Chaque sous-classe hérite de l’implémentation de l’objet et toutes les données sont toujours accessibles par simple itération sur des éléments ou par recherche de nom.</p><p>N’est-ce pas fantastique ? Alors, sommes-nous arrivés à un endroit qui méritait d’être vu ?</p>

Coin des développeurs
5 min de lecture
Optimiser les données partagées
<p>Quand vous pouvez voir la lenteur, mesurer la lenteur, dénicher quelle partie est lente, vous devez tout de même trouver une solution. Dans cet article, je vais vous expliquer un cas où j’ai vu, mesuré et localisé un problème. J’ai ensuite réglé ce problème et je vais maintenant vous expliquer comment j’ai procédé.</p><p>Une première mise en garde. Je ne présenterai pas le genre de technique étonnante, de bas niveau, bien documentée et mathématiquement prouvée, comme celle de Daniel Lemire. Pour voir un exemple de ce type d’optimisation, allez voir par exemple : “<a href="https://lemire.me/blog/2018/05/03/how-fast-can-you-parse-json/">How fast can you parse JSON?</a>”.</p><p>Ici, nous ne comptons pas les cycles du CPU. Dans cet article, je parle uniquement des optimisations simples qu’un programmeur de logiciels moyen peut faire au quotidien.</p><h2>Voir le problème</h2><p>Le programme sur lequel je travaillais était un filtre pour les gros fichiers texte organisés en arbre. C’est-à-dire que l’indentation de chaque ligne dans le fichier représentait le niveau d’imbrication. Quand je parle de gros fichiers, je veux dire traiter couramment 100 Mo à 1 Go de données de journal. Ce programme a été écrit en C++.</p><p>La 1<sup>re</sup> approche a consisté à lire le texte dans un vecteur de wstring (std::vector<std::wstring>). La raison de ce choix de départ est basée sur des principes bien connus sur la façon de choisir un conteneur en C++. Le premier principe est le suivant :</p><p><i><b>Utilisez toujours un std::vector</b></i>.</p><p>(Le deuxième principe est “utilisez un vecteur trié” et le troisième est “êtes-vous vraiment sûr qu’un vecteur ne fera pas l’affaire ?”)</p><p>Il était maintenant évident, lors de tests avec des fichiers de grande taille, que la lecture et le filtrage d’un si grand vecteur de chaînes de caractères étaient lents. Lorsque votre chronomètre est suffisant pour savoir que la performance n’est pas au rendez-vous, vous pouvez commencer à jeter un coup d’œil.</p><h2>Mesurer le problème</h2><p>Heureusement, il est très facile de jeter un coup d’œil grâce à Visual Studio. Même l’édition communautaire est livrée avec un très bon profileur CPU. Juste sous le menu “Debug”, l’entrée “Performance Profiler…” (raccourci : Alt+F2) ouvrira une fenêtre avec votre cible de projet déjà sélectionnée pour le profilage. De là, il vous suffit de cliquer sur le bouton “Start” et votre programme s’exécutera sous le profileur CPU. Faites simplement l’opération que vous souhaitez mesurer et quittez. Mesure effectuée !</p><p>Voici à quoi ressemble la fenêtre du profileur lorsqu’il enregistre les activités de votre programme :</p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4422/profiler_1.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4422/profiler_1.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4422/profiler_1.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4422/profiler_1.webp" style="width: 100%; border-style:solid; border-width:1px;" alt="Profiler" title="Profiler"></source></source></source></picture></p><h2>Localiser le problème</h2><p>Le profileur analysera les données et vous présentera une liste des fonctions où votre programme passe le plus de temps. Par défaut, cette liste est organisée en fonction du temps total du CPU, comme ceci :</p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4422/profiler_2.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4422/profiler_2.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4422/profiler_2.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4422/profiler_2.png" style="width: 100%; border-style:solid; border-width:1px;" alt="Profiler" title="Profiler"></source></source></source></picture></p><p>Si cela vous donne une vue d’ensemble, cela signifie également que vous voyez beaucoup de données non pertinentes. Vous pouvez toujours trouver facilement la zone problématique en recherchant des sauts importants dans le pourcentage de temps passé. De ce cas-ci, il s’avère que beaucoup de temps est passé à copier des chaînes de texte et à allouer de la mémoire. Les allocations de mémoire proviennent des chaînes de texte et du redimensionnement du vecteur. Il y a également un temps important passé dans les entrées/sorties des fichiers lors de la lecture du texte.</p><p>Nous disposons maintenant de quelques emplacements, nous sommes donc en mesure de trouver une solution au problème de performance.</p><h2>Emprunter quelques trucs</h2><p>Une bonne idée pour optimiser est de connaître les astuces que d’autres ont utilisées. Une réalisation importante est que lors du filtrage, le texte lui-même ne change pas. Seul ce qui est conservé ou non change. Ceci signifie que nous pouvons emprunter quelques astuces aux langages fonctionnels :</p><ul> <li><b><i>Les constantes peuvent être partagées</i></b>.</li> <li><b><i>Éviter de déplacer les données</i></b>.</li> <li><b><i>Déléguer la gestion de la mémoire</i></b>.</li></ul><p>L’idée est donc de rendre le texte partageable, de l’extraire le plus directement possible du disque et de lui ôter la gestion de la mémoire dans laquelle il réside. Nous allons donc faire ce qui suit :</p><ol> <li><b><i>Les constantes peuvent être partagées</i></b> : lire les données du disque dans de grandes mémoires tampon de données non modifiables.</li> <li><b><i>Évitez de déplacer les données</i></b> : recherchez des lignes de texte dans ces tampons et gardez des pointeurs directement dans le tampon.</li> <li><b><i>Évitez de déplacer les données</i></b> : partagez ces tampons et ces lignes de texte dans le résultat du filtrage.</li> <li><b><i>Déléguer la gestion de la mémoire</i></b> : partager ces tampons lors de la copie du texte.</li></ol><p>En bref, nous sommes passés du code :</p><pre><code>struct VectorOfWStringTextHolder { using Line = std::wstring; std::vector<Line> Lines; };</code></pre><p>À ce code:</p><pre><code>struct VectorOfSharedBuffersTextHolder { using Buffer = vector<wchar_t>; using BufferPtr = shared_ptr<Buffer>; using Buffers = vector<BufferPtr>; Buffers TextBuffers; using Line = wchar_t *; std::vector<Line> Lines;</code></pre><p>L’idée ici est qu’en utilisant un vecteur de tampons partagés, les adresses des tampons ne changent jamais et peuvent être facilement partagées entre plusieurs instances.</p><p>Bien sûr, ces changements ont rendu le code plus complexe. La complexité peut cependant être cachée, car les tampons peuvent rester privés et seul un vecteur de lignes peut être exposé publiquement. Le code a été simplifié ici pour s’assurer que les benchmarks mesurent ce que nous voulons mesurer.</p><h2>Les résultats</h2><p>Oui, des benchmarks ! Après tout, il est inutile d’optimiser si vous ne pouvez pas vérifier l’amélioration. En général, il suffit de réutiliser le profileur CPU et de voir les nouveaux résultats. Mais pour cet article, je suis allé plus loin et j’ai extrait l’essentiel de l’ancien et du nouveau code et j’ai écrit un petit programme de référence qui charge un gros fichier et fait des copies partielles des lignes de texte pour imiter le filtrage.</p><p>L’avantage d’écrire un benchmark explicite est que vous pouvez placer les mesures de temps exactement là où vous le souhaitez. De cette façon, vous ne mesurez que ce qui est prévu. Avec le profilage du CPU, l’ensemble du programme est mesuré et il est plus difficile d’en extraire les données pertinentes.</p><p>Voici les résultats. (J’ai exclu les temps d’entrée/sortie, mais la lecture dans de grands tampons et l’analyse directe des tampons ont donné un gain similaire.)</p><table style="width:100%"> <tbody> <tr> <th>Format des données</th> <th>Durée</th> </tr> <tr> <td style="vertical-align: top;"><i>Vector of strings</i></td> <td style="vertical-align: top;">13,28 s.</td> </tr> <tr> <td style="vertical-align: top;"><i>Shared buffers of shared lines</i></td> <td style="vertical-align: top;">1,2 s.</td> </tr> </tbody></table><p>Comme on peut le voir, nous avons obtenu une accélération d’un facteur de plus de 10. (En fait, nous avons obtenu une amélioration encore plus importante sur les fichiers plus volumineux, car la réallocation d’un très grand vecteur est très coûteuse).</p><h2>Le code</h2><p>J’ai fourni le code montrant divers benchmarks et une autre approche utilisant std::deque. J’avais également fait quelques benchmarks dans une structure arborescente dont je n’ai pas parlé ici. (Le changement n’a pas amélioré les performances dans ce cas, mais il a permis d’éviter un autre problème sans rapport avec la profondeur de récursion et le débordement de pile lors de la destruction de structures profondément liées de pointeurs partagés).</p><p>Vous pouvez trouver le code <a href="https://github.com/pierrebai/FastTextContainer">sur GitHub</a>.</p><p>Notez que l’utilisation réelle de cette technique se trouvait dans mon projet de filtrage d’arbre de texte, également disponible sur GitHub. L’optimisation a été faite dans TextTree et la façon dont il contient les données de texte à travers un TextHolder. Il utilise également une astuce similaire pour pouvoir avoir des adresses stables pour ses nœuds d’arbre en utilisant le fait souvent négligé qu’un std ::deque n’invalide pas les pointeurs lorsqu’on ajouter des données. Le code se trouve <a href="https://github.com/pierrebai/TreeReader">ici</a>.</p>

Coin des développeurs
5 min de lecture
Des Qwidget dans un QListWidget
<p>De plus, je voulais permettre de transférer les items entre plusieurs QlistWidget, via le glisser-déposer (<i>drag and drop</i>). Cela est facilement pris en charge dans le QListWidget standard. Le glisser-déposer permet de concevoir une interface utilisateur facile à utiliser et intuitive, et ça me semblait important à supporter.</p><p>Et pourtant, remplir ces deux conditions s’est avéré plus difficile que je ne l’avais prévu. Dans cet article, je vais survoler tous les obstacles que j’ai rencontrés et la solution finale, étonnamment simple, à tous ces problèmes.</p><h2>Premier essai</h2><p>La première approche naïve consiste à penser qu’il doit être possible d’ajouter simplement un QWidget contenant plusieurs sous-widgets dans un QListWidget. Il existe de nombreux exemples montrant une vue en liste contenant des cases à cocher. Ainsi, pour ajouter d’autres types de boutons, il faudrait simplement trouver la bonne fonction à appeler. Quelque chose doit être enterré dans la documentation Qt quelque part à ce sujet, n’est-ce pas ?</p><p>J’ai continué à fouiller dans la documentation de Qt, mais je n’ai jamais rien trouvé. Il s’avère que c’est tout simplement impossible.</p><p>Quand on y pense, il y a une raison pourquoi Qt ne permet pas de le faire. Le QListWidget peut contenir des milliers d’éléments dans une vue. Si chacun de ces éléments contenait plusieurs widgets, cela donnerait des milliers de widgets en même temps à l’écran. Étant donné que chaque widget fournit une interface riche, et donc beaucoup de données, ceci représente une charge très lourde. Au lieu de cela, Qt ne conserve que le strict minimum de données par élément dans la liste. Ce détail signifie que les widgets ne peuvent pas être placés directement dans une liste.</p><h2>Deuxième essai</h2><p>En cherchant dans la documentation de Qt, vous trouverez le concept de délégué d’item (QItemDelegate). C’est ainsi que Qt permet à l’usager de modifier les données d’un item dans une liste. Malheureusement, cette solution présente de nombreuses failles. L’interface utilisateur qui en résulte est non intuitive et difficile à découvrir, ce qui la rend inélégante.</p><p>L’utilisation d’un délégué est obscure, car les boutons ne sont pas visibles dans la liste. Pour faire apparaître les boutons, l’éditeur d’éléments doit être invoqué par l’utilisateur. L’utilisateur doit faire ce que Qt appelle une “action d’édition” : soit en appuyant sur F2, soit en double-cliquant. Ce ne sont pas des gestes qu’un utilisateur connaîtra. Il en résulte une interface utilisateur qui n’est pas intuitive ni facile à découvrir.</p><p>Il est également obscur, car tout cela nécessite que l’utilisateur sache déjà que l’item de la liste est modifiable…</p><p>Si seulement il y avait un moyen de montrer l’item en mode modifiable à tout moment…</p><h2>Troisième essai</h2><p>… mais il y en a un ! Le délégué d’item fournit une fonction de dessin qui peut être modifiée pour dessiner n’importe quoi. Mais comment dessiner n’importe quel autre widget ? Il y a en fait un moyen. Si vous regardez le code source pour savoir comment le widget de la liste standard peint la case à cocher, vous pouvez voir que Qt fournit des classes “style-option” pour dessiner les widgets. Mais si vous lisez la documentation, vous verrez qu’elle est très brève et plutôt incomplète. De plus, le support de toutes les fonctionnalités normales du widget, comme le survol et la sélection, nécessite beaucoup de code.</p><p>Et même si vous dessinez les widgets, ils ne sont toujours pas interactifs ! L’utilisateur doit toujours double-cliquer pour les rendre modifiables. Cela s’avère donc encore plus déroutant pour l’utilisateur.</p><p>Mais si cela ne suffisait pas, il y a encore un autre accroc. Le hic, c’est que les délégués ne peuvent être utilisés que par des modèles d’items (QAbstractItemModel) personnalisés. Vous ne pouvez pas utiliser un délégué avec un modèle d’items standard. Vous pourriez penser que ce n’est pas trop mal, que vous pourrez en créer un vous-même. Malheureusement, la mise en œuvre de votre propre modèle personnalisé n’est pas simple. Le problème est que Qt a des règles strictes sur la façon dont un modèle d’item doit se comporter. Il est difficile d’appliquer correctement toutes les règles, et tout écart entraîne un comportement étrange et des pépins très difficiles à diagnostiquer. Et ce, uniquement pour un modèle non éditable. Si vous voulez supporter le glisser-déposer, alors les règles sont encore plus complexes et impitoyables.</p><p>Le recours à un délégué entraîne donc l’écriture d’un grand nombre de lignes de codes dont la mise en œuvre et la maintenance sont très complexes. Il doit y avoir un meilleur moyen !</p><h2>Essai final</h2><p>Quelle est donc la bonne façon de mettre des widgets complexes dans une liste ? La réponse est d’une simplicité déconcertante : n’utilisez pas un widget de liste. Utilisez un widget simple. Oui, un simple QWidget.</p><p>Après tout, un QWidget peut contenir une liste arbitraire de sous-widgets. Bien entendu, vous devez alors ajouter la fonctionnalité standard d’une vue en liste par-dessus. Il faut supporter la sélection, le glisser-déposer et le défilement. Mais il s’avère que c’est beaucoup plus simple à écrire que les autres approches. Et, en prime, vous avez la garantie que le comportement de toutes les interfaces utilisateur que vous mettrez dans vos articles sera exactement le même que le comportement normal auquel l’utilisateur s’attend.</p><h2>La solution</h2><p>Ma solution au problème de la création d’un widget semblable à QListWidget pouvant contenir des widgets complexes est la suivante. Il y a quatre classes qui interagissent entre elles pour former la solution.</p><table style="width:100%"> <tbody> <tr> <th>Classe</th> <th>But</th> </tr> <tr> <td style="vertical-align: top;"><i>QWidgetListWidget</i></td> <td style="vertical-align: top;">Le widget qui contient les items.</td> </tr> <tr> <td style="vertical-align: top;"><i>QWidgetListItem</i></td> <td style="vertical-align: top;">Les éléments qui peuvent être mis dans la liste. Peut contenir un nombre quelconque de sous-widgets, de n’importe quel type.</td> </tr> <tr> <td style="vertical-align: top;"><i>QWidgetScrollListWidget</i></td> <td style="vertical-align: top;">Une enveloppe autour de QWidgetListWidget pour permettre le défilement.</td> </tr> <tr> <td style="vertical-align: top;"><i>QWidgetListMimeData</i></td> <td style="vertical-align: top;">Les données MIME utilisées pour supporter le glisser-déposer entre plusieurs QWidgetListWidget.</td> </tr> </tbody></table><h3>QWidgetListWidget</h3><p>C’est l’un des deux principaux points d’intérêt de la conception : le widget de liste. Cette vue de liste permet de sélectionner des éléments et de les faire glisser. Il fournit une interface simple, composée de quelques fonctions. Voici la déclaration en C++ de ces fonctions :</p><pre><code>// Créer une liste de widgets.QWidgetListWidget(ListModifiedCallbackFunction modifCallback, bool stretch, QBoxLayout::Direction dir, QWidget * parent);// Vérifiez si la liste est verticale ou horizontale.bool isVertical() const;// Enlever tous les éléments de la liste.void clear();// Ajouter un item.QWidgetListItem* addItem(QWidgetListItem* item, int index = -1);// Supprimer un élément.void removeItem(QWidgetListItem* item);// Récupérer tous les éléments conservés dans cette liste.std::vector<QWidgetListItem*> getItems(bool onlySelected = false) const;// Récupérer tous les éléments sélectionnés conservés dans cette liste.std::vector<QWidgetListItem*> getSelectedItems() const;</code></pre><h3>QWidgetLisItem</h3><p>C’est le deuxième point d’intérêt principal. C’est un élément qui peut être sélectionné et qui peut être cloné. Le clonage est utilisé lors du glisser-déposer pour copier un élément d’une liste à une autre. Voici l’interface complète en C++. Elle est assez courte :</p><pre><code>// Créer un item.QWidgetListItem(QWidget* parent);// Sélection.bool isSelected() const;void select(bool sel);// Clonage d’objets pour le glisser-déposer.virtual QWidgetListItem* clone() const;</code></pre><h3>QWidgetScrollListWidget</h3><p>Cette classe n’existe que pour que le défilement de la liste soit facultatif. Il peut sembler étrange de rendre le défilement optionnel, mais c’est assez pratique lorsque vous voulez intégrer la vue de la liste dans les éléments d’une autre vue de la liste. Toute l’interface C++ est simplement ceci :</p><pre><code>// Créer un widget défilant autour d’un autre widget.QWidgetScrollListWidget(QWidget * widget, QWidget* parent);</code></pre><h3>QWidgetListMimeData</h3><p>La dernière classe n’existe que pour le glisser-déposer. Vous ne devriez jamais avoir à l’utiliser directement. L’ensemble de son implémentation en C++ est la suivante :</p><pre><code>static constexpr char MimeType[] = "application/x-qwidget-list-item";QWidgetListItem* Widget = nullptr;QPoint HotSpot;</code></pre><h2>Le code</h2><p>L’intégralité de la mise en œuvre est <a href="https://github.com/pierrebai/QWidgetListWidget">disponible sur GitHub</a>.</p><p>Le code est accompagné d’un exemple d’application montrant comment utiliser les classes. Voir la description sur GitHub sur la façon de construire le projet.</p><p>Un exemple plus complexe peut être trouvé dans le projet TreeFilterApp. Il montre même comment placer des listes dans d’autres listes. Le code est également <a href="https://github.com/pierrebai/TreeReader">sur GitHub</a>.</p>

Bonnes pratiques
5 min de lecture
10 bonnes pratiques pour du code lisible
<p>Un jour ou l’autre, quelqu’un lira votre code et essaiera de comprendre quelle est sa finalité. Cette personne pourra même être vous-même… et il est bien possible que vous perdiez du temps à tenter de comprendre ce que vous avez écrit quelques mois plus tôt, parce que ce n’est plus très frais dans votre mémoire et parce que vous n’avez pas accordé suffisamment d’attention à la lisibilité.</p><p>J’ai eu l’occasion d’assister à une présentation sur les bonnes pratiques de rédaction de code faite par Jason McCreary (@<a href="https://twitter.com/gonedark">gonedark</a>). Si rien n’est en soi très révolutionnaire, c’est un ensemble de règles que j’ai trouvé intéressant de partager et qu’il me semble important de garder à l’esprit.</p><p>Jason propose une liste de 10 points à garder en tête pour que vous ou le programmeur suivant puisse comprendre facilement et intuitivement votre code. Pensez-y, si votre code est immédiatement compréhensible, il pourrait vous arriver de sauver la fin de semaine d’un collègue en support postproduction, ou celle d’un futur vous-même.</p><h2>Formater</h2><p>Il y a plein de normes et de possibilités. Il ne s’agit pas de débattre sur l’indentation par des tabulations ou par des espaces, ou encore des mérites comparés des styles Allman et K&R, mais plutôt de convenir d’une norme (par exemple <a href="https://www.php-fig.org/psr/psr-12/">PSR12</a>) et de s’y tenir. Les “CodeSniffer” et les environnements de développement (IDE) font très bien la détection automatique de violations d’une norme de codage définie et ils permettent de s’assurer de maintenir une base de code propre et cohérente. Soyez rigoureux et consistants.</p><h2>Code mort</h2><p>Le code est mort, effacez-le !!! Faites le ménage dans ces blocs commentés, ces variables inutilisées et ce code qui n’est jamais appelé. Voyez votre programme comme un arbre bien entretenu : il y a des moments où il faut couper le bois mort pour favoriser une croissance harmonieuse et éviter les accidents.</p><h2>Code imbriqué</h2><p>Si vous respectez le premier point et que votre indentation vous amène à commencer votre ligne en dehors des limites de l’écran, c’est un signe qu’il faut peut-être revoir votre approche. Évidemment les conditions imbriquées sont partie intégrante d’un code, mais, quitte à écrire des sous-fonctions, il faut garder en tête que le programmeur derrière vous n’a pas forcément le diagramme que vous aviez sous les yeux pour écrire vos conditions ! Démêlez le code imbriqué en utilisant des clauses de garde, des retours anticipés ou des aspects de la programmation fonctionnelle.</p><h2>Utiliser des <i>objects</i></h2><p>C’est une remarque un peu plus destinée aux programmeurs PHP, mais elle s’applique à bien d’autres langages. L’idée ici est de privilégier l’utilisation d’objets sur celle des tableaux. L’exemple le plus évident en PHP est l’utilisation de tableaux pour passer un nombre variable de variables.</p><h2>Gros blocs de code</h2><p>On le sait tous qu’une fonction de 500 lignes, c’est mal. Alors, n’en faites pas ! Jamais. Si vous traînez déjà un bloc de code atteignant une longueur critique, il est temps de le remanier en un bloc plus lisible et moins complexe.</p><h2>Dénomination</h2><p>“foo” est un nom de variable pour les exercices à l’école, pas un pour la vraie vie.</p><p>Si la fonction <code>getWeekReport</code> retourne un rapport pour un mois, c’est que ce n’est définitivement pas un bon nom.</p><p>Si la fonction <code>getReport</code> retourne uniquement un rapport pour une semaine, elle pourrait judicieusement s’appeler <code>getWeekReport</code>.</p><p>Si vous ne trouvez pas le bon nom tout de suite, continuez à coder et revenez-y plus tard. Ce ne doit pas être un bloquant et le nom parfait s’imposera de lui-même plus tard.</p><h2>Adieu les commentaires</h2><p>Voilà qui est un peu provocant, mais il faut en fait considérer les points suivants :</p><ol> <li>Les DocBlocks ne sont pas des commentaires ; on les aime et on en veut.</li> <li>Si vous avez besoin d’expliquer votre code avec du texte, c’est probablement que votre code est améliorable.</li> <li><code>$today = date(); // Set today date</code>. Ceci est un parfait exemple de commentaire non pertinent.</li> <li>Les commentaires ne sont pas interdits pour autant, par exemple s’ils servent à expliquer une règle d’affaires.</li> <li>On préfère de loin pas de commentaires du tout à des commentaires erronés !</li> <li>Au final, peu importe les commentaires, seul le code est exécuté. Seul le code compte vraiment.</li></ol><p>Mettez-vous donc au défi de réécrire le code pour qu’il n’ait pas besoin de commentaires.</p><h2>Valeurs de retour acceptables</h2><p>Un lecteur doit comprendre facilement ce que la fonction retourne. Certains préfèrent un seul retour dans la fonction. D’autres regroupent par type de retour (par exemple tous les <code>if … return true</code> au début, puis les <code>if return false</code> ensuite).</p><p>Idéalement, on doit éviter de pelleter dans le jardin du voisin les cas qui nous embêtent. Comme le <code>return null</code> qui implique que le cas <code>null</code> va probablement devoir être traité ailleurs.</p><h2>Règle des 3</h2><p>C’était nouveau pour moi et j’ai trouvé ce principe intéressant. Il s’illustre comme suit :</p><ul> <li>Si je vous demande ce qui vient après “2”, vous pouvez ne pas avoir de réponse. Ce peut être 3 ou 4, ou pourquoi pas 1 ou 2,1.</li> <li>Si je vous demande ce qui vient après “2, 4”, vous avez quelques idées, mais pas de certitude.</li> <li>Si je vous demande ce qui vient après “2, 4, 16”, vous pensez certainement à 256.</li></ul><p>C’est la règle des 3.</p><p>Dans le monde des programmeurs, cela signifie que votre code devrait suivre une logique. Il faut donc éviter les cas où votre code fait “2, 4, 6, 27” ! Votre code est peut-être juste et fait ce qu’il faut, mais c’est totalement contre-intuitif pour le lecteur.</p><p>Dans la même approche, si votre code fait “2, 4, <code>call function DonextStep</code>”, ça peut aussi nuire à la lisibilité de votre code. Cela implique de parfois devoir dupliquer votre code. Donc, oui, ça va à l’encontre du <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>... ¯\_(ツ)_/¯</p><h2>Symétrie</h2><p>Pour garder ce concept simple, je l’illustrerai en disant que si on a deux fonctions <i>create</i> et <i>update</i>, on s’attend alors à ce qu’elles prennent le même type de paramètres et retournent le même type de variable.</p><pre><code>Function update (User user) : boolean successFunction create(User user) : boolean success</code></pre><p>Plutôt que :</p><pre><code>Function update (int userId, User user) : boolean successFunction create(Array[]) : User user</code></pre><p>Si vous souhaitez approfondir ces principes, Jason McCreary a publié <i>BaseCode</i>, un guide dans lequel il développe davantage les différents points et les illustre par de nombreux exemples pratiques (disponible pour 29 $ sur <a href="https://basecodefieldguide.com">son site</a>). Vous pouvez aussi regarder des <i>screencasts</i> sur <a href="https://www.youtube.com/watch?v=s9LwS6RFax0&list=PLmwAMIdrAmK7cjLLYrKppUhaR2ywTuKhm&index=1">sa chaîne YouTube</a>.</p><p>Bon code!</p>

Coin des développeurs
5 min de lecture
Installer un octo-boot sur un Mac (partie 1)
<h2>Contexte</h2><p>En tant que directeur TI dans une entreprise de taille moyenne comme la nôtre, je dois accepter le fait que certains utilisateurs sont amenés à utiliser des produits Apple et qu’ils finiront très probablement par nous demander notre aide. Compte tenu de cela, nous devons disposer d’un appareil assez récent sur lequel est installé macOS, afin de pouvoir effectuer des tests ou des opérations de dépannage, mais la dernière fois que j’ai regardé, les conditions de licence d’Apple exigeaient que nous utilisions macOS à partir d’un produit Apple officiel. Récemment, j’ai récupéré un MacBook Pro 2015 lors d’une réparation gratuite pour un problème de batterie. Étant donné notre politique interne qui exige que nous remplacions le matériel tous les cinq ans, j’ai demandé à mon patron si je pouvais remplacer le disque interne du MacBook pour avoir une machine à triple démarrage à des fins TI (macOS, Microsoft et Linux). Il a accepté l’achat, à condition que je produise quelques articles de blogue sur mon expérience.</p><p>Mais après, j’ai commencé à réfléchir. Pourquoi pas quatre systèmes d’exploitation ? Et comme je manquais de sommeil ce jour-là, les choses ont fait boule de neige et j’ai fini par me convaincre d’avoir huit systèmes d’exploitation, parce que le mot “octuple” a un son plus cool et plus identifiable que le mot “nonuple” ou “septuple”. Alors, nous y voilà.</p><p><b>Avertissement !</b> Jouer avec les partitions, en particulier la partition de démarrage, n’est pas une activité pour les âmes sensibles ; cela peut même rendre votre appareil définitivement non démarrable. Ne faites pas ça à moins que vous ne soyez familier avec des trucs comme les partitions de disque, GRUB, EFI, etc.</p><p><b>Avertissement encore plus important !!!</b> Les gens de TI se parlent à eux-mêmes... beaucoup... Nous prétendons que c’est un processus, mais en fait, nous ne sommes que des épaves en manque de sommeil.</p><h2>Les bases</h2><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4330/octobot.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4330/octobot.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4330/octobot.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4330/octobot.webp" style="width: 100%; border-style:solid; border-width:1px;" alt="Octo-boot." title="Octo-boot."></source></source></source></picture></p><h3>Les grandes lignes du projet</h3><p>Officiellement, Apple supporte le double démarrage pour MacOS et Windows via Boot Camp, et la <a href="https://support.apple.com/en-us/HT201468">procédure</a> est assez simple. Cependant, lorsqu’il s’agit de triple démarrage avec une distribution Linux, les choses commencent à se gâter. Ceux qui font ce genre de choses recommandent d’utiliser un gestionnaire de démarrage appelé “<a href="http://www.rodsbooks.com/refind/">rEFInd</a>”. Il doit être installé manuellement à partir d’une clé USB pendant le processus. J’avais une liste de distributions Linux que je voulais installer, mais j’ai dû la modifier un peu en cours de route. Au moment de la rédaction, j’ai pratiquement atteint mon objectif d’avoir huit distributions sur la même machine grâce à un excellent article que j’ai trouvé <a href="https://robpickering.com/triple-boot-macbook-pro-macos-windows-10-linux/">ici</a>.</p><h3>Les systèmes d’exploitation</h3><p>En plus de Windows et de MacOS, nous avons installé une série de distributions Linux (ou distros en langage geek). Linux est le programme central, appelé noyau, auquel sont attachés une série d’outils et de programmes (environnement de bureau, système de fichiers, bibliothèques, etc.) afin de constituer un système d’exploitation complet.</p><p>Voici la liste des systèmes d’exploitation que j’ai fini par installer, avec la taille des partitions et la raison de l’installation :</p><ul style="list-style-type:disc;"> <li><b>macOS</b> <ul style="list-style-type: circle;"> <li>Taille : 256 Go.</li> <li>OS : Duh... (basé sur FreeBSD).</li> <li>Raison : en avoir un pour l’équipe et mettre à l’épreuve des outils de gestion d’entreprise prévus.</li> </ul> </li> <li><b>Windows 10 Pro</b> <ul style="list-style-type: circle;"> <li>Taille : 256 Go répartis entre le disque C: pour l’OS et le D: qui est partagé entre les OSs.</li> <li>Environnement de bureau : MS Windows.</li> <li>Raison : faire tourner Crysis.</li> </ul> </li> <li><b>Linux Mint</b> <ul style="list-style-type: circle;"> <li>Taille : 64 Go.</li> <li>Environnement de bureau : Cinnamon Desktop, basé sur Ubuntu.</li> <li>Raison : LinuxMint est généralement ma distribution de référence pour l’implémentation de l’environnement de bureau et, comme je la connais bien, c’est aussi ma “référence de contrôle” dans cette expérience.</li> </ul> </li> <li><b>Suse Linux</b> <ul style="list-style-type: circle;"> <li>Notes : <ul style="list-style-type: square;"> <li>J’avais l’intention d’utiliser une distro basée sur Gentoo, mais elles sont connues pour être difficiles à utiliser et plus orientées vers les serveurs. Sabayon ne voulait même pas lancer le processus d’installation et Redcore n’arrivait pas à faire fonctionner le Wi-Fi (sans compter les dépôts basés en Russie).</li> <li>Je suis passé à Suse Linux parce que sa principale base de développement se trouve en Allemagne et que tout le monde sait que tout ce qui est allemand est bien conçu (et cool).</li> </ul> </li> <li>Taille : 64 Go.</li> <li>Environnement de bureau : KDE Plasma, basé sur Slackware.</li> <li>Raison : l’Allemagne !!! Tester le système de fichiers <a href="https://en.wikipedia.org/wiki/Btrfs">Btrfs</a>.</li> </ul> </li> <li><b>Manjaro</b> <ul style="list-style-type: circle;"> <li>Taille : 64 Go.</li> <li>Environnement de bureau : KDE, basé sur Arch Linux.</li> <li>Raison : expérimentation de repo Arch (Pacman).</li> </ul> </li> <li><b>Fedora</b> <ul style="list-style-type: circle;"> <li>Taille : 64 Go.</li> <li>Environnement de bureau : Mate Desktop, basé sur Redhat.</li> <li>Raison : cette distro basée sur RedHat est l’une des plus importantes distributions de Linux et utilise la gestion de repos YUM.</li> </ul> </li> <li><b>Kali Linux</b> <ul style="list-style-type: circle;"> <li>Taille : 128 Go.</li> <li>Environnement de bureau : GNOME Desktop, basé sur Debian.</li> <li>Raison : les tests de sécurité. Cette distribution est préchargée avec un large éventail d’outils de sécurité pour le piratage éthique.</li> </ul> </li> <li><b>Ubuntu Studio</b> <ul style="list-style-type: circle;"> <li>Taille : 128 Go.</li> <li>Environnement de bureau : XFCE, basé sur Ubuntu, avec un noyau soi-disant à faible latence.</li> <li>Raison : avoir une distro orientée vers les trucs artistiques et tester la fonctionnalité du noyau à faible latence si possible.</li> </ul> </li></ul><h3>Objectifs d’après-installation</h3><p>Les objectifs qui en découlent sont les suivants :</p><ul style="list-style-type:disc;"> <li><i>Tester une variété de distributions et d’interfaces utilisateurs :</i> <ul style="list-style-type: circle;"> <li>Les distributions Linux sont plus ou moins réputées pour leur flexibilité.</li> <li>Cela peut rendre le support quelque peu difficile et aléatoire dans certains cas en raison de la grande variété de matériel disponible.</li> <li>Sur une distribution donnée, vous pouvez disposer d’un large éventail de gestionnaires de fenêtres.</li> <li>J’ai essayé de choisir l’assortiment le plus large possible d’environnements de de bureau et de prendre ceux qui étaient fournis “prêts à l’emploi” avec l’installation de la distro. <ul style="list-style-type: square;"> <li>Vous pouvez généralement choisir le bureau de votre choix après avoir installé le bureau “par défaut”.</li> <li>J’ai choisi de prendre ceux qui étaient “officiellement” pris en charge pendant la phase d’installation afin de réduire les problèmes.</li> </ul> </li> </ul> </li> <li><i>Disposer d’une partition de disque partagée par tous les systèmes d’exploitation :</i> <ul style="list-style-type: circle;"> <li>Je le fais généralement avec toute machine à double démarrage que j’utilise, afin de faciliter l’accès à divers fichiers tels que les photos, les fichiers musicaux, les vidéos, etc.</li> <li>Comme Windows n’a traditionnellement jamais pris en charge les systèmes de fichiers autres que FAT et NTFS, j’ai toujours partagé un disque “D:” formaté en NTFS.</li> </ul> </li> <li><i>Faire en sorte que les éléments suivants soient testés et fonctionnent :</i> <ul style="list-style-type: circle;"> <li>Caméra ;</li> <li>Emplacement pour carte SD ;</li> <li>Moniteur externe ;</li> <li>Gestion de l’alimentation ;</li> <li>Fonctions spéciales ; <ul style="list-style-type: square;"> <li>Grâce à une combinaison de touches contrôle, option et commande, vous pouvez contrôler divers aspects de la machine, tels que la luminosité et le volume.</li> <li>Toutes les fonctionnalités doivent être présentes dans tous les systèmes d’exploitation.</li> </ul> </li> <li>Casque externe USB ;</li> <li>Casque externe 3,5 ;</li> <li>Carte d’interface réseau filaire ;</li> <li>Réseau Wi-Fi ;</li> <li>Boîtier externe basé sur USB.</li> </ul> </li> <li><i>Tests de différentes applications et tests de charge :</i> <ul style="list-style-type: circle;"> <li>Navigateur Firefox. <ul style="list-style-type: square;"> <li>Trouver un site web/application qui soit exigeant en ressources et obtenir des statistiques.</li> </ul> </li> <li>Navigateur Chrome. <ul style="list-style-type: square;"> <li>Installer et lancer la version officielle de Google.</li> </ul> </li> <li>Système de fichiers. <ul style="list-style-type: square;"> <li>Copie de fichiers.</li> <li>“Zipper” avec NTFS et avec le système de fichiers propre à chaque OS.</li> <li>Documenter chaque système de fichiers.</li> </ul> </li> <li>Logiciel pour tests vidéo et audio. <ul style="list-style-type: square;"> <li>Afin de comparer les performances, trouver un outil qui convertit des fichiers vidéo/audio dans un autre format et qui peut être utilisé sur toutes les plateformes.</li> </ul> </li> <li>Outil de compilation. <ul style="list-style-type: square;"> <li>À déterminer. Idéalement, un outil multiplateforme accompagné de quelque chose à compiler qui soit assez lourd pour prendre au moins cinq minutes sous macOS.</li> <li>Je demanderai à mes collègues de m’aider sur ce point.</li> </ul> </li> <li>Wi-Fi/filaire, téléchargement/latence. <ul style="list-style-type: square;"> <li>Trouvez un outil qui peut être utilisé avec tous les systèmes d’exploitation et qui fournit une multitude de statistiques.</li> </ul> </li> <li>Outil de rendu 3d. <ul style="list-style-type: square;"> <li>Test avec Blender.</li> </ul> </li> </ul> </li></ul><h2>Matériel et installation initiale</h2><p>Le disque du Mac Pro 2015 est relativement facile à accéder et remplacer tant que vous disposez des bons outils. Je n’entrerai pas dans les détails ici, mais sachez que les vis sont du type “<a href="https://en.wikipedia.org/wiki/Pentalobe_security_screw">pentalobe</a>” et qu’elles sont faciles à enlever. J’ai commandé un disque NVMe chez <a href="https://www.macsales.com">OWC</a> parce que je m’attends à ce qu’un disque NVMe ordinaire ne fonctionne pas comme prévu, ce que je vérifierai à la fin du projet. Ma première (semi)surprise a été de trouver un disque NVMe Samsung à l’intérieur d’un ordinateur portable Apple. Cela montre que si les deux sont en désaccord en public, ils se retrouvent dans le même lit en privé. La réinstallation du logiciel macOS et l’installation de Windows qui a suivi se sont déroulées sans problème avec Boot Camp. Je ne vais pas passer en revue tout le processus ici, car il est amplement couvert dans de nombreux autres articles.</p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4330/samsung-ssd.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4330/samsung-ssd.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4330/samsung-ssd.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4330/samsung-ssd.webp" style="width: 100%; border-style:solid; border-width:1px;" alt="Samsung S4LN058A01-8030." title="Samsung S4LN058A01-8030."></source></source></source></picture></p><p>NVMe SSD Samsung.</p><p>Le plaisir commence vraiment avec l’installation de Linux. En gros, chaque fois que vous installez une distribution Linux, elle installe GRUB (sauf SuSe), ce qui fait que macOS s’arrête de démarrer alors que tout le reste fonctionne encore. La solution que j’ai trouvée a été de réinstaller l’application rEFInd à chaque fois, mais j’ai ensuite réalisé que je devrais également réinstaller rEFInd à chaque fois qu’une distribution Linux reçoit un nouveau noyau dans sa mise à jour. J’ai essayé de trouver une solution en éditant manuellement le fichier GRUB avec quelques modifications suggérées par divers forums, mais en vain. Cela nécessitera quelques recherches. Un autre problème que j’ai rencontré était que Windows ne démarrait plus non plus, et j’ai dû désactiver la protection de l’intégrité du système (<a href="https://en.wikipedia.org/wiki/System_Integrity_Protection">SIP</a>).</p><p>En dehors de ces petits désagréments, j’ai été très surpris de constater que le Wi-Fi fonctionnait à peu près sans problème sur toutes les distros que j’ai fini par installer. C’était ma plus grande crainte. Les pilotes Wi-Fi sont généralement la composante la plus problématique dans l’installation d’une distribution Linux, étant donné que les puces Wi-Fi sont souvent liées à des pilotes fermés.</p><p>Le plus gros problème que j’ai rencontré a été l’affichage sur le portable, qui s’est avéré quelque peu inégal. Ça fonctionnait tout de suite dans certains cas, mais d’autres nécessitaient quelques réglages. Toutes les plateformes ont souffert de quelques bogues ici et là, provoqués par l’écran Retina de ce modèle de portable. Cet écran est certes très beau, mais quelques ajustements sont nécessaires pour qu’il soit utilisable. Habituellement, les problèmes ont été (principalement) résolus en cherchant sur Google les paramètres HiDPi pour les différentes plateformes. En fin de compte, le seul irritant qui restait était dans le gestionnaire de boot login de l’écran GRUB, sur lequel je ferai des recherches plus tard.</p><h2>Et maintenant ?</h2><p>Quelque part dans le processus, je me suis un peu emporté et j’ai oublié de prendre des notes sur les ajustements d’interface dans les environnements de bureau. Je crois que je vais simplement relancer les procédures d’installation et noter les détails de chaque distro dans la partie 2 ou 3 de cette série d’articles de blogue. Je dois faire quelques recherches sur la question de GRUB pour voir si je peux faire quelque chose à ce sujet ou si je dois simplement m’en tenir à “rEFInd”. Comme mentionné précédemment, jouer avec le bootloader est quelque peu risqué et la documentation sur le sujet est maigre. Chaque fois que je trouvais un article à ce sujet, il y avait toujours une restriction. Idéalement, j’aimerais avoir GRUB comme mon bootloader permanent et le faire fonctionner de manière continue et cohérente à travers les mises à jour du noyau Linux. Le plan B serait de supprimer l’installation par défaut de GRUB, puisque rEFInd peut détecter assez bien les nouveaux OS.</p>

Stratégie
5 min de lecture
Aider une équipe à gérer de lourdes contraintes
<p>Voici quelques conseils qui peuvent vous venir en aide :</p><p>Une contrainte très lourde peut souvent être considérée par les membres de l’équipe comme impossible à surmonter à première vue, ce qui entraîne des réactions négatives. <b>Rappeler à l’équipe votre confiance dans sa capacité à trouver une solution</b>, et passer en revue les différents processus et phases qui mènent à la découverte d’une solution aidera grandement l’équipe à vivre avec le doute et l’incertitude de la situation.</p><p>En tant que chef d’équipe, <b>votre rôle consiste à aider votre équipe à atteindre son objectif</b> et à tirer des leçons de l’expérience. Évitez d’imposer vos idées à l’équipe ; assurez-vous plutôt que chacun se sente à l’aise d’exprimer les siennes. Aucune idée ne devrait être passée sous silence par crainte d’être jugée ou de subir une pression des pairs.</p><p>Assurez-vous que <b>toutes les idées peuvent être remises en question par les membres de l’équipe</b> et que des résultats constructifs découlent de ces remises en question. La pensée critique permet d’éviter la <a href="https://fr.wikipedia.org/wiki/Pens%C3%A9e_de_groupe">pensée de groupe</a> au sein d’une équipe et aide à atteindre des sommets. L’équipe doit être consciente que ce qui peut être mis en question est l’idée et non la personne qui l’a proposée.</p><p>Le fait de ne pas imposer vos idées à l’équipe ne signifie pas que vous n’avez pas votre mot à dire sur ce que l’équipe propose. Si la solution ne répond pas à vos attentes, ou si vous croyez qu’il y a une meilleure façon de procéder, <b>vous pouvez mettre l’équipe au défi</b>. Une bonne façon de le faire est de poser des questions de fond pour amener le groupe à comprendre comment les choses pourraient être mieux faites et à apprendre à être plus critique à l’égard de leurs conclusions.</p><p><b>Les membres de l’équipe doivent savoir que vous et l’organisation êtes là pour les soutenir.</b> Ils doivent avoir confiance que vous vous occuperez de toutes les questions qui ne sont pas directement liées au problème qu’ils essaient de résoudre et que vous leur accorderez le temps, le budget, les talents et les ressources nécessaires.</p><p><b>La voie vers la solution optimale passe par les succès et les échecs.</b> Les conséquences d’un échec ne devraient jamais être l’amertume ou le blâme. L’échec est une occasion pour l’équipe de comprendre ce qui a mal tourné et ce qui a bien fonctionné, et de décider de la suite des opérations. L’échec est une source de connaissance et de meilleure compréhension du problème. Il est une nouvelle étape dans le voyage intellectuel vers la solution définitive. Utilisez l’échec comme une rampe de lancement pour atteindre un niveau supérieur.</p><p>Les accomplissements modestes comme les grandes victoires aident à <b>créer une énergie positive</b> et une attitude constructive.</p><p><b>Célébrez les accomplissements</b> tout au long du processus pour motiver l’équipe.</p><p>N’oubliez pas que la solution qui semble la plus simple est en fin de compte souvent celle qui a demandé le plus de travail et d’inventivité : <b>trouver des solutions simples est très difficile</b>.</p>

Coin des développeurs
5 min de lecture
Mes trucs et astuces favoris dans Visual Studio
<p>Bonjour ! Aujourd’hui, j’ai pensé à partager mes meilleurs trucs pour gagner du temps avec Visual Studio.</p><p>Juste pour que vous le sachiez, je travaille généralement en C++ et C#, mais la plupart de ces conseils devraient s’appliquer aussi bien à d’autres langages.</p><p>On y va.</p><h2>Astuces d’édition</h2><p>1. <b>Aller n’importe où : Ctrl + ,</b></p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/01_go_to_all.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/01_go_to_all.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/01_go_to_all.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4218/01_go_to_all.png" style="width: 452px; border-style:solid; border-width:1px;" alt="Go to All" title="Go to All"></source></source></source></picture></p><p>Cet outil vous permet de trouver rapidement tout et n’importe quoi (fichiers, classes, etc.) dans votre projet.</p><p>2. <b>Aller à l’emplacement de saisie précédent : Ctrl + -</b></p><p>3. <b>Passer à l’emplacement de saisie suivant : Ctrl + Shift + -</b></p><p>4. <b>Aller au début ou à la fin d’un bloc de code : Ctrl + [ et Ctrl + ]</b></p><p>5. <b>Aller à la définition : F12</b></p><p>Un outil de base, mais essentiel pour naviguer rapidement vers les définitions de classes et de méthodes.</p><p>6. <b>Mettre en commentaire le bloc de code sélectionné : Ctrl + K + C</b></p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/02_comment_block.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/02_comment_block.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/02_comment_block.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4218/02_comment_block.png" style="width: 224px; border-style:solid; border-width:1px;" alt="Comment out the selected block of code" title="Comment out the selected block of code"></source></source></source></picture></p><p>7. <b>Décommenter le bloc de code sélectionné : Ctrl + K + U</b></p><p>8. <b>Formater automatiquement le code sélectionné : Ctrl + K + F</b></p><p>Ceci corrige automatiquement les espaces et l’indentation du code en fonction de vos paramètres.</p><p>9. <b>Boîte de sélection verticale de texte : Alt + clic souris</b></p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/03_alt_box_select.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/03_alt_box_select.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/03_alt_box_select.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4218/03_alt_box_select.webp" style="width: 213px; border-style:solid; border-width:1px;" alt="Vertical text box-selection" title="Vertical text box-selection"></source></source></source></picture></p><p>Cela est très utile pour supprimer les premiers caractères du texte sur plusieurs lignes de code.</p><p>10. <b>Basculer entre un en-tête et son fichier source (C++) : Ctrl + K + O</b></p><p>11. <b>Renommer une variable : Ctrl + R + R</b></p><p>C’est beaucoup plus rapide que de trouver manuellement chaque occurrence de la variable par vous-même.</p><p>12. <b>Afficher les espaces : Ctrl + R + W</b></p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/04_whitespace.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/04_whitespace.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/04_whitespace.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4218/04_whitespace.png" style="width: 195px; border-style:solid; border-width:1px;" alt="View whitespace" title="View whitespace"></source></source></source></picture></p><p>C’est peut-être mon TOC, mais j’adore voir avec exactitude les espaces dans un document. Et je n’aime pas avoir à deviner si c’est une tabulation ou un espace.</p><p>13. <b>Extraits de codes <i>(snippets)</i></b></p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/05_code_snippets.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/05_code_snippets.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/05_code_snippets.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4218/05_code_snippets.png" style="width: 611px; border-style:solid; border-width:1px;" alt="Code snippets" title="Code snippets"></source></source></source></picture></p><p>Si vous vous trouvez en train d’écrire les mêmes instructions à plusieurs reprises, envisagez d’utiliser des extraits de code.</p><p>Voici un exemple pour vous aider à démarrer : je travaille souvent en mode Release pour accélérer les choses dans le cadre d’un très gros projet client.</p><p>Lorsque j’ai besoin de déboguer une méthode de manière plus approfondie, je peux rapidement désactiver les optimisations en tapant le raccourci suivant : P + O + Tab.</p><p>Avant, je devais écrire encore et encore : <code>#pragma optimize("", off)</code>.</p><p>Pour cela, il me suffit d’associer un raccourci clavier (Outils -> Options -> Environment -> Clavier) à l’extrait de code suivant :</p><pre><code><?xml version="1.0" encoding="utf-8" ?><CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <CodeSnippet Format="1.0.0"> <Header> <Title>Pragma Optimize Off</Title> <Shortcut>po</Shortcut> <Description>Code snippet to disable optimizations</Description> <Author>Me</Author> <SnippetTypes> <SnippetType>Expansion</SnippetType> </SnippetTypes> </Header> <Snippet> <Code Language="cpp">#pragma optimize("", off)</Code> </Snippet> </CodeSnippet></CodeSnippets></code></pre><h2>Trucs de débogage</h2><p>14. <b>Actions de points d’arrêt <i>(breakpoints)</i></b></p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/06_breakpoint_action.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/06_breakpoint_action.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/06_breakpoint_action.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4218/06_breakpoint_action.png" style="width: 100%; border-style:solid; border-width:1px;" alt="Breakpoint Action" title="Breakpoint Action"></source></source></source></picture></p><p>Utilisez des actions de points d’arrêt au lieu de <code>printf</code> ou <code>cout</code>. J’adore les actions : elles vous permettent d’ajuster rapidement vos logs temporaires sans recompiler à chaque fois et sans oublier de les nettoyer quand ils ne sont plus nécessaires.</p><p>15. <b>Points d’arrêt conditionnel</b></p><p>Un outil de débogage de base très utile. Il se trouve juste à côté des actions dans le panneau des options de points d’arrêt.</p><p>16. <b>Exécuter jusqu’au curseur : “Run execution to here”. Pas besoin de point d’arrêt !</b></p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/07_run_execution_to_here.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/07_run_execution_to_here.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/07_run_execution_to_here.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4218/07_run_execution_to_here.png" style="width: 231px; border-style:solid; border-width:1px;" alt="Run to cursor" title="Run to cursor"></source></source></source></picture></p><p>Je sais que certains trouvent ce widget ennuyant, mais il n’a pas à n’être qu’un piège à curseur de souris. Essayez d’appuyer sur le petit bouton vert Play pour sauter rapidement à ce point du code pendant le débogage. Grâce à cet outil, il n’est plus nécessaire d’ajouter un point d’arrêt temporaire pour s’arrêter au point souhaité.</p><p>17. <b>Faire glisser le pointeur d’instruction</b></p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/08_instruction_pointer.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/08_instruction_pointer.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4218/08_instruction_pointer.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4218/08_instruction_pointer.png" style="width: 100%; border-style:solid; border-width:1px;" alt="Drag the instruction pointer" title="Drag the instruction pointer"></source></source></source></picture></p><p>Oui, vous pouvez déplacer la flèche jaune pendant le débogage. Il est très utile de pouvoir la déplacer vers le haut dans le code que vous déboguez pour répéter l’exécution de certaines instructions de code. Vous pouvez aussi facilement sauter des blocs de code pendant le débogage en les faisant glisser vers le bas. La beauté est ici que vous pouvez le faire sans redémarrer l’application à chaque fois.</p><h2>Pour conclure</h2><p>J’espère que vous avez découvert une astuce ou deux pour accélérer votre flux de travail quotidien de codage. Ajoutez vos propres favoris dans la section de commentaires ci-dessous !</p><p>À la prochaine !</p>

Stratégie
5 min de lecture
Donner vie à une idée grâce au processus Découverte
<p>Il arrive qu’une entreprise ait identifié une problématique à résoudre sans avoir une idée précise de la solution à apporter. Il peut s’agir par exemple d’adapter l’entreprise à de nouvelles réalités de son marché, de gagner en vélocité, de moderniser des outils ou de trouver une réponse à un besoin de ses clients. Ça peut aussi être l’amélioration d’un produit existant ou la création d’un nouveau.</p><p>Inspiré du <i><a href="https://www.spiria.com/fr/blogue/design-uxui/innover-avec-le-design-sprint/">Design Sprint</a></i> de Google mais plus flexible dans sa formule et plus large dans son champ d’application, le processus Découverte a été développé par Spiria afin d’aider les entreprises à innover. Il consiste en une période de collaboration intense et interactive qui fait appel à différents outils suivant le type de problématique à résoudre.</p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4178/spiria-dev.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4178/spiria-dev.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4178/spiria-dev.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4178/spiria-dev.webp" style="width: 100%; border-style:solid; border-width:1px;" alt="Spiria Montréal." title="Spiria Montréal."></source></source></source></picture></p><p>Réunissant une équipe d’experts du numérique, les décisionnaires et diverses parties prenantes, le processus se déroule en 4 phases :</p><h2>1. Préparation</h2><p>Cette phase est consacrée à la compréhension du métier du client, de son écosystème et du défi à relever sous tous ses angles et perspectives. Nous parlons de développer une vision à 360°. Elle peut être accompagnée de divers travaux préparatoires comme la recherche de documentation, la réalisation d’un sondage auprès de futurs utilisateurs ou la réalisation d’une synthèse des chiffres clés du marché.</p><h2>2. Définition</h2><p>Après la phase préparatoire de compréhension, les participants s’attellent à circonscrire le problème central, à rassembler les attentes et à définir l’objectif central du processus. Ils établissent également les bonnes métriques du succès et recensent les éventuelles contraintes comme une architecture dans laquelle s’insérer.</p><h2>3. Idéation</h2><p>Le but de cette phase est de tracer les parcours utilisateurs et créer un story-board détaillé de la solution envisagée. Il inclut les caractéristiques et les fonctionnalités essentielles d’un produit minimum viable. Si nécessaire, on définira une maquette fonctionnelle (<i>wireframe</i>), on posera les bases d’une architecture de l’information et d’une approche méthodologique, on fera une revue technique afin de juger de la faisabilité.</p><h2>4. Création</h2><p>Le story-board est transformé en prototype par une équipe multidisciplinaire et on définit : la quantité de travail nécessaire, la pile technologique, la liste des fonctionnalités, le tout permettant d’estimer le coût de la solution numérique finale. Avec une feuille de route précise, il est alors possible de passer à la phase de production en ayant limité les impondérables et en assurant une productivité maximale.</p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4178/healthpro.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4178/healthpro.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4178/healthpro.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4178/healthpro.webp" style="width: 100%; border-style:solid; border-width:1px;" alt="HealthPRO website." title="HealthPRO website."></source></source></source></picture></p><p>HealthPRO, un site corporatif conçu de A à Z dans des délais record grâce au processus Découverte. <a href="https://www.spiria.com/fr/realisations/healthpro/">En savoir plus</a>.</p><p>Suivant la problématique, différents documents peuvent être produits à la fin d’un processus Découverte : une feuille de route, des maquettes, un guide de style, un corpus rédactionnel (<i>copy deck</i>) structuré, des tests d’utilisabilité, etc.</p><p>Pour l’essentiel, qu’il s’agisse de répondre à un besoin de l’entreprise ou de concrétiser une idée aux contours plus ou moins flous, l’objectif du processus est de bâtir dans un délai minimum les solides fondations qui permettront de démarrer avec sérénité et efficacité une phase de développement. Un <a href="https://www.spiria.com/fr/services/strategie-de-croissance/processus-decouverte/">processus Découverte</a> ne laisse aucune zone d’ombre, produit une feuille de route détaillée et donne une vision précise du résultat final. Il diminue les risques inhérents à tout projet de développement logiciel, s’avérant ainsi un investissement immédiatement rentable.</p>

Culture
5 min de lecture
Évoluer et créer des liens par le jeu
<p>Je ne travaille pas avec mes collègues.</p><p>Ce qui devrait être paradoxal, mais qui est en fait une réalité pour quiconque travaille dans une entreprise avec une grande variété de clients, comme une agence numérique ou une société de conseil. J’ai beaucoup de collègues, dont certains font partie de plus importantes équipes pour des clients plus importants, mais avec notre gamme de clients, il se trouve que mes coéquipiers directs ne sont pas à notre bureau de Gatineau. C’est un concept très nouveau pour moi.</p><p>J’ai travaillé pour des entreprises en démarrage, ce qui, à bien des égards, contraste fortement avec mon environnement actuel. Dans une jeune pousse, vous avez un groupe relativement restreint de personnes qui travaillent à la réalisation d’un objectif, d’un produit ou d’un seul projet. Jour après jour, la plupart d’entre nous se concentrent sur les mêmes tâches et sur la résolution des mêmes problèmes. L’effort commun nous unit.</p><p>Chez <a href="https://www.spiria.com/fr/">Spiria</a>, par contre, on pourrait supposer, comme je l’ai déjà fait, que ne pas travailler directement avec mes collègues m’éloignerait d’eux. Eh bien, je suis heureux de dire que c’est loin d’être le cas. Nous interagissons tous encore tous les jours, que ce soit lors de discussions techniques, de résolution collaborative de problèmes, de déjeuners d’équipe ou de parties de baby-foot à l’heure du dîner.</p><p>Un aspect intéressant de notre interaction, celui que j’aimerais souligner aujourd’hui, c’est qu’un grand nombre d’entre nous s’intéressent aux jeux de société. Mais contrairement aux jeux relativement ordinaires de notre enfance, comme <i>Monopoly</i> et <i>Clue</i>, nos jeux sont moins dépendants de la chance. Ils favorisent la stratégie, la tactique, la collaboration ou la compétition, et tirent profit de systèmes et de mécanismes complexes qui font marcher le jeu. C’est une activité qui fait travailler nos esprits, un peu comme notre emploi, mais dans un cadre amusant et social.</p><p>Nous avons maintenant au bureau un petit stock de jeux, apportés par ceux d’entre nous qui ont plus qu’un nombre raisonnable de jeux à la maison. Cela nous donne des activités impromptues à faire au déjeuner, après le travail, les fins de semaine, ou même lorsque les gens ont juste besoin de s’éloigner de leur moniteur et de s’engager dans quelque chose qui continue à faire travailler leur cerveau.</p><p><picture><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4113/board-games.400x0.webp" media="(max-width: 599px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4113/board-games.760x0.webp" media="(max-width: 999px)"><source type="image/webp" srcset="https://mirror.spiria.com/site/assets/files/4113/board-games.1039x0.webp" media="(min-width: 1000px)"><img src="https://mirror.spiria.com/site/assets/files/4113/board-games.webp" style="width: 100%; border-style:solid; border-width:1px;" alt="Spirians playing Rising Sun." title="Spirians playing Rising Sun."></source></source></source></picture></p><p>Des Spiriens jouent à <i>Rising Sun</i>.</p><p>Les jeux favorisent la pensée critique, une qualité dont nous avons besoin en tant que développeurs pour notre travail quotidien. Certains jeux nous demandent d’observer et de connaître les divers traits et personnalités des autres joueurs, nos collègues de travail. Cela nous aide à mieux les connaître et les comprendre, ce qui favorise la collaboration lorsque nous travaillons ensemble sur des projets.</p><p>Même si je suis nouveau ici, cette activité nous a déjà réunis à de nombreuses reprises en dehors du travail. Il a encouragé ceux d’entre nous qui sont plus introvertis à s’engager socialement avec leurs collègues de manière amusante et sans stress. À de nombreuses reprises, je suis descendu tard pour le déjeuner pour découvrir une partie déjà en cours, tandis que d’autres s’asseyaient autour, observant et discutant les différentes actions et stratégies en jeu.</p><p>Les mécanismes du jeu suscitent l’intérêt dans nos esprits et le lien créé par l’expérience commune nous rapproche.</p>