<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Packmind</title>
    <description>The latest articles on DEV Community by Packmind (@packmind).</description>
    <link>https://dev.to/packmind</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4301%2Fe845520a-839b-4ba2-8c20-14c21340e266.png</url>
      <title>DEV Community: Packmind</title>
      <link>https://dev.to/packmind</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/packmind"/>
    <language>en</language>
    <item>
      <title>From Code Reviews to Team Growth: Unlocking the Power of Practice Reviews</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Thu, 31 Aug 2023 20:08:10 +0000</pubDate>
      <link>https://dev.to/packmind/from-code-reviews-to-team-growth-unlocking-the-power-of-practice-reviews-hho</link>
      <guid>https://dev.to/packmind/from-code-reviews-to-team-growth-unlocking-the-power-of-practice-reviews-hho</guid>
      <description>&lt;p&gt;In 2008, GitHub revolutionized how we approached code by introducing its Pull-Request model for code reviews. Initially adopted by open-source projects, they were used as checks to review the code from possibly anonymous contributors and make sure they made the product better. Fast forward to today, while this model has been widely adopted, its potential is not fully harnessed, as reviews continue to be used as mere checks. For high-performing teams, the stakes are higher. Beyond checking code quality, they foster collaboration, continuous learning, and &lt;strong&gt;knowledge sharing&lt;/strong&gt;. These are first-class concerns for engineering managers and tech leaders. &lt;/p&gt;

&lt;p&gt;Knowledge sharing is the engine driving efficiency, agility, innovation, and growth. Rethink your approach to code reviews. View them not just as a procedural step, but as a platform to amplify knowledge sharing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prioritize discussions on coding standards and best practices, primarily in Pull/Merge Requests’ comments. Remember: Every comment is an opportunity to elevate, not just evaluate.&lt;/li&gt;
&lt;li&gt;Limit immediate discussions to issues that hinder code from being production-ready. File away secondary discussions for later, asynchronous engagements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine if every &lt;strong&gt;code review&lt;/strong&gt; taught something new to your whole team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maximizing the Impact of Code Reviews
&lt;/h2&gt;

&lt;p&gt;Previously, we did a &lt;a href="https://www.packmind.com/accelerate-code-reviews/" rel="noopener noreferrer"&gt;deep dive&lt;/a&gt; into the '&lt;a href="https://www.packmind.com/accelerate-code-reviews/" rel="noopener noreferrer"&gt;Ship/Show/Ask&lt;/a&gt;' framework, which empowers Pull Request authors to determine one of the following next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No review is needed for trivial changes (Ship)&lt;/li&gt;
&lt;li&gt;Share code changes with peers for feedback (Show). Note: feedback can be provided after the merge.&lt;/li&gt;
&lt;li&gt;Seek a review for significant/critical code changes (Ask)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In code review, spotlight potential bugs, security/legal concerns, ensuring resolution before deployment. One oversight? Code review feedback often remains confined to the author, leaving the team in the dark. Relevant insights should be accessible to all. Moreover, tech leaders often complain about the need to explain the same concepts in 1:1 threads &lt;a href="https://www.packmind.com/code-review-gitlab-linter-rules/" rel="noopener noreferrer"&gt;repeatedly&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, discussions on code readability or maintainability should ideally be &lt;strong&gt;deferred&lt;/strong&gt;. Why? These conversations typically involve broader team perspectives and, when prematurely debated, can derail the development flow, and increase the lead time for change.&lt;/p&gt;

&lt;p&gt;So, when's the ideal time for these high-stake discussions? Enter: &lt;strong&gt;Practice Reviews&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Harnessing the Power of Practice Reviews
&lt;/h2&gt;

&lt;p&gt;Think of practice reviews as collaborative spaces for developers, whether in teams or broader communities (guilds, &lt;a href="https://www.packmind.com/community-of-practice-in-software-engineering-teams/" rel="noopener noreferrer"&gt;community of practice&lt;/a&gt;, …), aimed at:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fostering knowledge-sharing and discussions about &lt;strong&gt;coding practices&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Formulating and aligning with new coding standards&lt;/li&gt;
&lt;li&gt;Leveraging and sharing developer expertise&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;NB: Note that a coding practice can address topics such as a programming language, a framework, security, architecture, design, performance, and more.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Scheduled regularly (perhaps weekly or bi-weekly) and clocking in at around an hour, practice reviews are disconnected from the code release process, and address source code that may have been already pushed into production. Unlike code reviews, they have no impact on the lead time.&lt;/p&gt;

&lt;p&gt;The practices review’s agenda includes source code snippets annotated with a suggestion of coding practices, a discussion topic, or a question. These insights can come from code reviews, coding session, or virtually anywhere.&lt;/p&gt;

&lt;p&gt;Each insight is introduced by its contributor, paving the way for team discussions, clarifications, and collective learning. By session end, the team not only adopts new coding standards but also amplifies its shared technical expertise. To go further, check how Ubisoft &lt;a href="https://www.packmind.com/ubisoft-knowledge-sharing-scale/" rel="noopener noreferrer"&gt;gets value&lt;/a&gt; from these practice reviews. &lt;/p&gt;

&lt;h2&gt;
  
  
  Code Reviews and Practice Reviews: A Synergy
&lt;/h2&gt;

&lt;p&gt;Code reviews are focused 1:1 discussions, ensuring code-readiness for production, typically multiple times weekly. They drive asynchronous interactions. As code reviews &lt;strong&gt;block the delivery process&lt;/strong&gt;, they pressure developers and prevent them from diving into deeper discussions about coding practices, so they lose a chance to elevate as a team. &lt;/p&gt;

&lt;p&gt;In contrast, practice reviews are team-centric workshops. Held weekly or several times per month, they combine asynchronous code insights from code reviews or code changes with synchronous discussions. This approach enhances knowledge sharing and refines coding standards. Inversely to code reviews, &lt;strong&gt;they don’t block the delivery process&lt;/strong&gt;, so developers are freed from any constraint and can dive deep into technical discussions with their team. &lt;/p&gt;

&lt;p&gt;Over time, practice reviews not only improve the overall code quality but streamline subsequent code reviews. Ensuring all developers know your coding standards brings confidence that the source code will gain consistency and will be easier to maintain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fpractices-reviews-1536x630.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fpractices-reviews-1536x630.png" alt="(Credits - Kent Beck)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For engineering managers and tech leaders, practice reviews are a powerful ally to foster collaboration, continuous learning, and knowledge sharing among software engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Packmind for practice reviews
&lt;/h2&gt;

&lt;p&gt;Recognizing the huge upside for development teams, we have built Packmind (ex-Promyze) as your partner to foster knowledge sharing and manage coding practices. Seamlessly integrated with your IDEs, code review platforms, and code repository, it offers a platform for sharing insights and curate coding practices. Example: A coding practice queued for a practice review:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2F0-gdZZo6GTbj_8ztRT.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2F0-gdZZo6GTbj_8ztRT.png" alt="A practice review"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition, the Packmind platform proactively scans for coding practices within your IDEs or during code reviews, providing an immediate feedback loop to developers. The development team remains in sync with the evolving best practices, fostering a culture of continuous learning.&lt;/p&gt;

&lt;p&gt;Discover more about Packmind and embark on your practice review journey &lt;a href="https://packmind.com" rel="noopener noreferrer"&gt;here 🚀&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>codereview</category>
      <category>programming</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>7 frustrations to avoid with code review best practices</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Fri, 26 May 2023 08:55:19 +0000</pubDate>
      <link>https://dev.to/packmind/7-frustrations-to-avoid-with-code-review-best-practices-4hl9</link>
      <guid>https://dev.to/packmind/7-frustrations-to-avoid-with-code-review-best-practices-4hl9</guid>
      <description>&lt;p&gt;Code review is one of the most established processes in software engineering. Recent studies indicate that almost &lt;a href="https://media.trustradius.com/product-downloadables/DD/D7/XID8MVZTH0JF.pdf"&gt;90% of IT companies&lt;/a&gt; practice it. The emergence of AI technologies brings since 2022 new tools to improve the code review experience. &lt;/p&gt;

&lt;p&gt;While its maturity has unveiled some common best practices for code reviews, it also emphasized several frustrations for developers in this context. At Packmind, we discussed their code review process with many technical leaders, engineering managers, and developers for several years. We’re especially interested in their improvement fields and what pains they still have. This post summarizes our findings. &lt;/p&gt;

&lt;h2&gt;
  
  
  Frustration 1: Spend too much time to understand the context and the code
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Lucas submitted a Pull Request to Sara. She realizes it contains 800 lines (”whao!”) scattered among 40 files. There are 3 commits with the respective messages: 1/ “Add new feature” 2/ “Fix bug” 3/ “Fix bug for good”. The PR description simply indicates “Add new features on product listing”. “I have no idea what I’m gonna read”, sighs Sara.&lt;/em&gt;*&lt;/p&gt;

&lt;p&gt;What frustrates Sara is the lack of clear context, leading to a more significant effort from her to dive into the code and understand it. Also, its size is an issue. There is tons of web content about what should be the ideal size of the code review. It depends on the context, and there’s no silver bullet. As the submitter, you should preview the Pull Request to gain empathy for the reviewer. This person will have a &lt;strong&gt;diff-based&lt;/strong&gt; perception of your changes, which is not your vision of your changes. &lt;/p&gt;

&lt;p&gt;As a submitter, soon as you start working on your code, think about how this code will be reviewed. Try to build atomic commits will clear and concise messages, and give a proper description to the PR. This &lt;strong&gt;context&lt;/strong&gt; will help the reviewer understand what you’ve achieved and save precious time, avoiding frustrations. If the commit messages are too long, that’s a bad smell of a commit that encompasses too many changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frustration 2: Bikeshedding and debating about standards
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Sara reads the review comments made earlier by Sofia. One is about a coding style that “doesn’t change the behavior, but I prefer like this”. Sara is annoyed because she wrote the code like many other parts of the software, so she wanted to keep consistency. She tells Sofia, “Both solutions are okay, but maybe it’s better to keep the current way of doing this?”. But Sofia argues it’s a chance to bring a new evolution in our coding practices. Sara gets frustrated because this debate delays the review completion.&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;Sometimes, don’t you regret that code reviews tools don’t limit the length of discussion threads? While some reviews might be critical and require a deep analysis, most of the time they do not. If the review is a discussion space to improve a piece of code, the scope of the suggestions made should be limited and known by all reviewers. In the scenario below, the problem is that Sofia began a discussion that goes beyond the scope of the review because it’s about a coding standard; this should involve the &lt;strong&gt;whole team&lt;/strong&gt; in making such a decision. &lt;/p&gt;

&lt;p&gt;Comments should target what’s necessary to update in the code before it gets merged. All other discussion topics should be addressed in a dedicated session gathering all developers in the team. That’s the framework suggested by &lt;a href="https://packmind.com"&gt;Packmind&lt;/a&gt;, whose code review extensions offer a smooth way to convert code review comments into coding practice suggestions; this practice will be discussed and validated (or not) during a workshop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frustration 3: Spend time reviewing trivial code
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Sara starts reviewing a pull request from John, including two modified files and less than 20 lines of code changed. She’s in the middle of an emergency, but still took the time to do the review to avoid a latency for John. She approves the PR, but wonders why she was called to review that code. John could have done it himself!&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Rigorous process right? A solution is to consider that not all code changes &lt;strong&gt;deserve the same attention&lt;/strong&gt;. Some changes will be pretty basic and target non-critical parts of the system. Inversely, some changes will be more complex, impacting the application's core logic, or requiring strong attention regarding security concerns. We met several companies that have a &lt;strong&gt;rigorous process&lt;/strong&gt; of code review, including, for instance, three reviews before validation. But does it make sense to follow this process every time without consideration of the review material? &lt;/p&gt;

&lt;p&gt;Depending on the code submitted, we could imagine that developers are free to merge if they consider there’s no risk and need to assign a reviewer, and they should ask for two reviewers if the code changes are critical. That’s the idea promoted by the &lt;a href="https://martinfowler.com/articles/ship-show-ask.html"&gt;Ship Show Ask&lt;/a&gt; model. With solutions like &lt;a href="https://reviewpad.com/"&gt;Reviewpad&lt;/a&gt;, you can implement your assignment and merge rules depending on the content of the review. &lt;/p&gt;

&lt;h2&gt;
  
  
  Frustration 4: Getting few valuable feedbacks
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Sara carefully submitted the review: she created isolated commits with clear messages and added detailed context in the PR description. It was the first time she had worked on this part of the software, so she took care to avoid any mistakes and expected to get constructive feedback. The PR contains about 400 hundred added lines. Stefan took the review but only wrote on comment: “LGTM”. Sara is relieved but expected a bit more material.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Maybe Sara just did the job perfectly, right? Even if it’s true, a good practice during the code review is to provide positive feedback on the code, to highlight what’s been done correctly. People often emphasize what’s “bad” and forget to comment when the work done is fine. This refers to &lt;strong&gt;empathy&lt;/strong&gt;: Sara paid attention to the quality of the submission, and Stefan probably felt that, so he should also show empathy towards her. &lt;/p&gt;

&lt;p&gt;To optimize the quality of the feedback, the reviewers must allow a sufficient amount of time for the review.  Otherwise, they’ll extract only shallow and superficial content. And the submitter will feel that. So better don’t do the review if you’re in a hurry or not in the mindset for that. Ask a colleague to replace you this time. Also, adapt your expectations depending on who’s gonna make the review (her technical skills and expertise on the code, …). If the reviewer has few knowledge of the context, maybe it’s best to ask for a second review from a more advanced developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frustration 5: The latency until the review gets completed
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Sara opens a pull request at 01:00 pm. She asks her team if someone can review her changes. Bob will show up at 3:40 pm. and, after spending 5 mins reviewing, will suggest one minor change. Sara immediately takes 2 min to apply the change and asks Bob to approve the new version of the code. Bob approves at 5:00 pm, and the code is shipped in production. The whole process lasted 4 hours, but stuff happened only for 7 minutes. Fortunately, only one reviewer was required!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The first step is to focus on the root problem: why is this latency significant during the process? Do reviewers lack time because they’re overwhelmed? Don’t they pay enough attention to their notifications from the code review tool? Or is it because you don’t like to review, so they procrastinate as much as possible? The whole completion time indeed depends on the availability of the reviewer. There’s no silver bullet here, but this problem must be discussed internally to identify how to improve this process.&lt;/p&gt;

&lt;p&gt;Between the PR creation until it’s merged, the majority of the time, nothing will happen. We wait for the next step to happen. Unfortunately, that idle time hurts the delivery time (&lt;a href="https://www.packmind.com/compute-dora-metrics-tools/"&gt;the lead time for changes&lt;/a&gt;). While they wait for a review, developers will be tempted to start another task, leading to context-switching. Practicing &lt;strong&gt;mob programming&lt;/strong&gt; can prevent such latencies. Also, a solution like &lt;a href="https://axolo.co/"&gt;Axolo&lt;/a&gt; offers a Slack application to manage GitHub pull requests and reduce the Pull Request merge time. &lt;/p&gt;

&lt;h2&gt;
  
  
  Frustration 6: Getting unpleasant or hurtful comments
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.packmind.com/discovering-the-code-review/"&gt;egoless programming&lt;/a&gt; principles stand as core concepts for doing great code reviews. One stipulates that &lt;em&gt;“You’re not your code”&lt;/em&gt;. Code review, such as any other discussion space in a Tech organization, should be respectful among the participants. So we’re all kind to each other, and we formulate constructive comments about how to improve the code. Even though you’re uncomfortable with the code you’re reading, there’s no reason to write something like: &lt;em&gt;“This is a non-sense, and this code should be thrown away”.&lt;/em&gt; Be constructive instead: &lt;em&gt;“What do you think about this alternative instead?”.&lt;/em&gt; If developers are stressed or feel bad before getting review comments, your team has a severe problem to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frustration 7: The source code has obvious bugs
&lt;/h2&gt;

&lt;p&gt;If you review a code and immediately say, &lt;em&gt;“Hey, how this code possibly works?”&lt;/em&gt;, this does not smell like a great start. But you might be wrong and have missed something. So you politely ask to code author: &lt;em&gt;“I’m possibly wrong, but I think this code has an issue and does not have the expected behavior since …”&lt;/em&gt;. If the answer is, “&lt;em&gt;Oh yes, my bad, I didn’t run it actually.”&lt;/em&gt; I can definitively understand your frustration ;-) This is an apparent lack of rigor and empathy from the code author. To avoid this, set guidelines and rules before submission; for instance: code must have been tested (manually) and/or covered by unit tests, linters should have been executed, and the CI/CD pipeline is checked, …&lt;/p&gt;

&lt;p&gt;Feel free to share with us your main frustrations when doing code reviews; we’d be happy to read them. To go further, we suggest you read our dedicated post on how to accelerate &lt;a href="https://www.packmind.com/accelerate-code-reviews/"&gt;the code review process&lt;/a&gt;. Thanks for reading ;)&lt;/p&gt;

</description>
      <category>codereview</category>
      <category>codequality</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Don't let your coding standards die in a wiki</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Tue, 25 Apr 2023 13:54:15 +0000</pubDate>
      <link>https://dev.to/packmind/dont-let-your-coding-standards-die-in-a-wiki-cbk</link>
      <guid>https://dev.to/packmind/dont-let-your-coding-standards-die-in-a-wiki-cbk</guid>
      <description>&lt;p&gt;In software engineering organizations, there’s this challenge to define, record and spread best coding practices and standards across teams. This brings consistency to source code and improves its maintainability. It also avoids bottlenecks and endless discussions during &lt;a href="https://www.packmind.com/accelerate-code-reviews/"&gt;code reviews&lt;/a&gt; on a given coding practice. A common approach to this challenge is building a knowledge base in a Wiki-like tool, such as Confluence or Notion. Although the idea makes sense and is relevant, at Packmind, we’ve talked with companies that shared the pitfalls and drawbacks of this approach for managing their coding standards. We discuss them in this post. &lt;/p&gt;

&lt;h2&gt;
  
  
  Raising and maintaining the practices repository is complex
&lt;/h2&gt;

&lt;p&gt;The most observed pattern can be summarized with the following picture: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CM_gGb3x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Notion_outdated-modified.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CM_gGb3x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Notion_outdated-modified.png" alt="Notion_outdated-modified.png" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are 2 details here that reflect the pitfalls of most wikis: The “&lt;strong&gt;TODO&lt;/strong&gt;” section and the “&lt;strong&gt;Last update&lt;/strong&gt;” property. Keeping an up-to-date wiki requires energy and effort from a group of people (mainly technical leaders). Most of the job is often achieved when bootstrapping the process since there is a solid motivation to build a knowledge base of coding practices. But this motivation tends to lower after several months, mainly because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It takes time to identify and raise the practices, write them, and find the appropriate positive and negative examples (Do/Don’t);&lt;/li&gt;
&lt;li&gt;This feeling that content gets a few hits and engagement from other developers (so why should I continue?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a consequence, most of the companies we talked with shared with us the “outdated wiki” pattern when we discussed their best coding practices management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engaging engineers is too neglected
&lt;/h2&gt;

&lt;p&gt;Knowledge has value only if it’s shared and understood by others. But having great content in your Wiki does not guarantee that people will interact with it. Do they even know it exists? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ojqh6CUs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Escobar_wiki_notread.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ojqh6CUs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Escobar_wiki_notread.webp" alt="https://www.promyze.com/wp-content/uploads/Escobar_wiki_notread.webp" width="590" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If not, they won’t search for it. It’s common that engineers looking for answers to their questions receive as answer a link to the appropriate Wiki page because they’ll be more likely to directly ask their colleagues instead of searching in the knowledge base. &lt;/p&gt;

&lt;p&gt;Coding practice shouldn't be built independently by a small group of engineers &lt;strong&gt;without collaboration and discussion with others engineers&lt;/strong&gt;. Think about how best practices are shared once written down in a Wiki. If a developer receives a message saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hey, I’ve added new 4 React coding practices to follow in our Wiki. Take a look here!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Do you think it’s engaging? We’ve got plenty of stuff to do, and you’ve already decided they’re all valid. So I’ll wait until someone tells me in a future code review that I don’t follow them. What if, instead, the same developers get this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hey, I came up with 4 React coding practices that I think could be helpful in our context. I want to introduce them to the team, discuss them, and decide if we validate or discard them. Would you be available for a short 30-min meeting this Friday?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More engaging right? Developers feel more involved in the construction process. And maybe they’ll have great suggestions to make!&lt;/p&gt;

&lt;h2&gt;
  
  
  Static content is not appropriate when coding
&lt;/h2&gt;

&lt;p&gt;Developers seldom code in their IDE while interacting with the knowledge base to see if they follow or not a coding standard. Ideally, they need to get the &lt;strong&gt;right information when they need it&lt;/strong&gt;. They should be notified &lt;strong&gt;i&lt;/strong&gt;f their code is not compliant with a practice. But Notion or Confluence are not designed for this specific use case. And when coding, we want to stay focused on our IDE. &lt;/p&gt;

&lt;p&gt;That’s why static should become &lt;strong&gt;dynamic&lt;/strong&gt; instead: how to push a coding practice when it’s relevant? How to create a bi-directional flow between developers and the knowledge base?  &lt;/p&gt;

&lt;h2&gt;
  
  
  Create Living Coding Practices
&lt;/h2&gt;

&lt;p&gt;If this post reminds you of your current context, you’re likely looking for alternatives to improve how you manage your best practices. Here is one for you. At Packmind, our ambition is to design a dedicated solution to this coding standards-sharing challenge. Our platform allows to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Raise coding standards from IDE and during code reviews thanks to our extensions;&lt;/li&gt;
&lt;li&gt;Validate them during collective workshops;&lt;/li&gt;
&lt;li&gt;Create a &lt;strong&gt;living coding practice&lt;/strong&gt; by enriching it with patterns (regular expressions, SemGrep patterns, …), and making it available for developers when they write or review source code;&lt;/li&gt;
&lt;li&gt;Support onboarding of new engineers with interactive challenges to learn the current practices in the organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learn more on &lt;a href="http://packmind.com"&gt;packmind.com&lt;/a&gt; to find more on this.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>35 Knowledge base tools for developers in 2023</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Fri, 14 Apr 2023 11:37:25 +0000</pubDate>
      <link>https://dev.to/packmind/35-knowledge-base-tools-for-developers-in-2023-3pij</link>
      <guid>https://dev.to/packmind/35-knowledge-base-tools-for-developers-in-2023-3pij</guid>
      <description>&lt;p&gt;In 2023, there should be no debate about the added value of great documentation in software projects. Software engineers should have access to the appropriate knowledge base, depending on the resource type and when they need it. Technical documentation for software developers can take many forms, including evergreen documentation (e.g., procedures for setting up a project), architectural principles that developers should follow in their projects, release documentation, &lt;strong&gt;&lt;a href="https://www.promyze.com/create-best-coding-practices/" rel="noopener noreferrer"&gt;coding standards&lt;/a&gt;&lt;/strong&gt; and guidelines, onboarding guides, and more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation for technical audiences&lt;/strong&gt; is a tough challenge for many reasons: it requires a rigorous organization to be kept up-to-date. It can quickly be put aside by engineers who often dislike spending time on maintaining documentation. One common mistake is to consider all categories of documentation at the same level: an ever-green procedure to install software is not the same as a coding standard, for instance, which regularly evolves. You don’t need this knowledge at the same time and frequency. Once you understand that, you can define different processes and channels to manage your technical documentation&lt;/p&gt;

&lt;p&gt;In this post, we provide an overview of 35 existing tools for managing technical knowledge, which can be scattered into these main categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Wiki-like tools&lt;/strong&gt; where engineers write documentation in the tool’s UI (ex: Notion, Confluence, …)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Living knowledge&lt;/strong&gt; tools, where knowledge emerges from developers’ tools and become then dynamic, are used for instance, in code analysis and onboarding sessions (ex: Packmind);&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Communication&lt;/strong&gt; tools, such as Questions/Answers platforms (ex: StackOverflow for Teams, …)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Generated-wiki&lt;/strong&gt; tools where developers will typically write documentation in markdown, and then all the magic will happen (ex: ReadTheDocs, …)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post does not consider tools that provide &lt;em&gt;end-user&lt;/em&gt; documentation, such as self-service portals (Zendesk, Intercom, etc.). We focus on documentation made by developers for developers. We also exclude API documentation tools, which belong to a specific domain that deserves its article.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://acreom.com/" rel="noopener noreferrer"&gt;Acreom&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Capture notes, break down issues, track your progress, create a knowledge base.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Facreom-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Facreom-1024x613.png" alt="Acreom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.answerhub.com/" rel="noopener noreferrer"&gt;AnswerHub&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Empowering developers and teams to learn, share, and succeed through online communities and knowledge sharing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fanswerhub-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fanswerhub-1024x613.png" alt="AnswerHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://appflowy.io/" rel="noopener noreferrer"&gt;AppFlowy&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Open Source Notion Alternative&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fappflowy-1024x613.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fappflowy-1024x613.webp" alt="AppFlowy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.archbee.com/" rel="noopener noreferrer"&gt;Archbee&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Build better product documentation — faster&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Farchbee-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Farchbee-1024x613.png" alt="Archbee"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="http://bit.ai/" rel="noopener noreferrer"&gt;Bit.ai&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Next-Gen Document Collaboration Platform for Teams!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fbitai-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fbitai-1024x613.png" alt="Bit.ai"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.bookstackapp.com/" rel="noopener noreferrer"&gt;BookStack&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(Open Source) BookStack is a simple, self-hosted, easy-to-use platform for organizing and storing information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fbookstack-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fbookstack-1024x613.png" alt="Bookstack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://clickup.com/" rel="noopener noreferrer"&gt;ClickUp&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Save time with the all-in-one productivity platform that brings teams, tasks, and tools together in one place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fclickup-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fclickup-1024x613.png" alt="ClickUp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://coda.io/" rel="noopener noreferrer"&gt;Coda&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The all-in-one doc for teams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fcoda-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fcoda-1024x613.png" alt="Coda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.codestream.com/" rel="noopener noreferrer"&gt;CodeStream&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;New Relic CodeStream is a free open-source extension for VS Code, Visual Studio, and JetBrains.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fcodestream-1-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fcodestream-1-1024x613.png" alt="CodeStream"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.atlassian.com/software/confluence" rel="noopener noreferrer"&gt;Confluence&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Confluence is your remote-friendly team workspace where knowledge and collaboration meet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fconfluence-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fconfluence-1024x613.png" alt="Confluence"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://daux.io/" rel="noopener noreferrer"&gt;Daux.io&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(OpenSource) The Easiest Way To Document Your Project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fdauxio-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fdauxio-1024x613.png" alt="Daux.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://developerhub.io/" rel="noopener noreferrer"&gt;DeveloperHub.io&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;All-in-One Platform for Online Documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fdeveloperhub-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fdeveloperhub-1024x613.png" alt="DeveloperHub.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://docusaurus.io/" rel="noopener noreferrer"&gt;Docusaurus&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(OpenSource) Build optimized websites quickly, focus on your content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fdocusaurus-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fdocusaurus-1024x613.png" alt="Docusaurus"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://flarum.org/" rel="noopener noreferrer"&gt;Flarum&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(Open Source) Forums made simple. Modern, fast, and free!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fflarum-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fflarum-1024x613.png" alt="Flarum"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.forem.com/" rel="noopener noreferrer"&gt;Forem&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(Open Source) Forem is an open source platform for building modern, independent, and safe communities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fforem-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fforem-1024x613.png" alt="Forem"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.gitbook.com/" rel="noopener noreferrer"&gt;GitBook&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Where software teams break knowledge silos. (We use it at Promyze for our &lt;a href="https://docs.promyze.com" rel="noopener noreferrer"&gt;public documentation&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fgitbook-1-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fgitbook-1-1024x613.png" alt="GitBook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;GitHub Pages&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Websites for you and your projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fgithubpages-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fgithubpages-1024x613.png" alt="GitHub Pages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://gohugo.io/" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(OpenSource) The world’s fastest framework for building websites.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fhugo-1-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fhugo-1-1024x613.png" alt="Hugo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://jekyllrb.com/" rel="noopener noreferrer"&gt;Jekyll&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Transform your plain text into static websites and blogs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fjekyll-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fjekyll-1024x613.png" alt="Jekyll"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://rust-lang.github.io/mdBook/" rel="noopener noreferrer"&gt;mdBook&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;static site generator from Markdown files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fmdbookf-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fmdbookf-1024x613.png" alt="mdBook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.mkdocs.org/" rel="noopener noreferrer"&gt;MkDocs&lt;/a&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  (Open Source) Project documentation with Markdown.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fmkdocs-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fmkdocs-1024x613.png" alt="MkDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://notion.so/" rel="noopener noreferrer"&gt;Notion&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The all-in-one workspace — for your tasks, notes, wikis, and calendar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fnotion-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fnotion-1024x613.png" alt="Notion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://notaku.so/product/docs" rel="noopener noreferrer"&gt;Notaku&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Build a full-featured Docs website in minutes, using Notion as CM&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fnotaku-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fnotaku-1024x613.png" alt="Notaku"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.nuclino.com/" rel="noopener noreferrer"&gt;Nuclino&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A modern, simple, and blazingly fast way to collaborate — bring knowledge, docs, and projects together in one place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fnuclino-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fnuclino-1024x613.png" alt="Nuclino"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://papyrs.com/" rel="noopener noreferrer"&gt;Papyrs&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The easiest way to create an online for your company.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fpapyrs-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fpapyrs-1024x613.png" alt="Papyrs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://readthedocs.org/" rel="noopener noreferrer"&gt;Read The Docs&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(Open Source) Read the Docs simplifies software documentation by automating building, versioning, and hosting of your docs for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Freadthedocs-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Freadthedocs-1024x613.png" alt="Read the docs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://skydocs.skyost.eu/" rel="noopener noreferrer"&gt;SkyDocs&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(OpenSource) SkyDocs is a lightweight static documentation builder with MarkDown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fskydocs-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fskydocs-1024x613.png" alt="SkyDocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://slab.com/" rel="noopener noreferrer"&gt;Slab&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Build a culture of knowledge-sharing today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fslab-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fslab-1024x613.png" alt="Slab"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.sphinx-doc.org/" rel="noopener noreferrer"&gt;Sphinx&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(OpenSource) Sphinx makes it easy to create intelligent and beautiful documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fsphinx-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fsphinx-1024x613.png" alt="Sphinx"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://stackoverflow.co/teams/" rel="noopener noreferrer"&gt;Stack Overflow For Teams&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Knowledge sharing and collaboration without distractions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fstackoverflow-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fstackoverflow-1024x613.png" alt="Stack Overflow for teams"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://swimm.io/" rel="noopener noreferrer"&gt;Swimm&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Documentation Platform Built for Engineers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fswimm-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fswimm-1024x613.png" alt="Swimm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://backstage.io/docs/features/techdocs/" rel="noopener noreferrer"&gt;TechDocs&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Spotify’s docs-like-code plugin for Backstage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Ftechdocs-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Ftechdocs-1024x613.png" alt="Techdocs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://tettra.com/" rel="noopener noreferrer"&gt;Tettra&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The best way to organize and share knowledge with your teammates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Ftettra-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Ftettra-1024x613.png" alt="Tettra"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://js.wiki/" rel="noopener noreferrer"&gt;Wiki.js&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;(OpenSource) The most powerful and extensible open source Wiki software&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fwikijs-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fwikijs-1024x613.png" alt="wiki.js"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://packmind.com/" rel="noopener noreferrer"&gt;Promyze&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Connect Developers’ Knowledge and share best coding practices, fully integrated in developers tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fpromyze-1-1024x613.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2Fpromyze-1-1024x613.png" alt="Promyze"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s all, folks; we hope that post gave you an overview of the current landscape of the knowledge base tools for software developers.&lt;/p&gt;

&lt;p&gt;Among the ones quoted above, at Promyze, we use Notion to gather material such as procedures to create new releases of our IDE extensions. We use GitBook to publish the user documentation of our platform. Finally, we use our tool Promyze internally to raise new coding standards continuously. We bring these standards directly in IDEs &amp;amp; during code reviews since we consider this is the moment developers need this knowledge. You don’t code with a Wiki opened in a tab.&lt;/p&gt;

&lt;p&gt;For each &lt;a href="https://www.packmind.com/knowledge-management-tooling-software-developers/" rel="noopener noreferrer"&gt;kind of documentation&lt;/a&gt;, you must define who should update it, when, and how other engineers will be notified of this change.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>tooling</category>
      <category>devops</category>
    </item>
    <item>
      <title>How a start-up implemented hexagonal architecture – The case of Packmind</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Mon, 27 Mar 2023 15:19:00 +0000</pubDate>
      <link>https://dev.to/packmind/how-a-start-up-implemented-hexagonal-architecture-the-case-of-promyze-2ke8</link>
      <guid>https://dev.to/packmind/how-a-start-up-implemented-hexagonal-architecture-the-case-of-promyze-2ke8</guid>
      <description>&lt;p&gt;Our platform &lt;a href="https://packmind.com"&gt;Packmind&lt;/a&gt; is developed in a Client-Server model with a Front side developed in TS and React, while our back-end relies on Node.js. To give some context, the code base started 3 years ago, and we’ve always been a small team with max. 4 developers working on the code simultaneously. We currently have 156 KLOC in our back-end and 154 KLOC on the front-end. &lt;/p&gt;

&lt;p&gt;Our &lt;strong&gt;motivations&lt;/strong&gt; for implementing concepts from &lt;a href="https://www.happycoders.eu/software-craftsmanship/hexagonal-architecture/"&gt;hexagonal architecture&lt;/a&gt; were to support the &lt;strong&gt;maintainability&lt;/strong&gt; of our code base, and ease our life when working on it to add new features.  When we discovered concepts from &lt;a href="https://www.packmind.com/why-read-red-book-domain-driven-design/"&gt;Domain-Driven Design&lt;/a&gt;, Clean &amp;amp; Hexagonal Architecture, we liked the idea of building &lt;strong&gt;separate bounded contexts&lt;/strong&gt; and having in our code domains that encapsulate &lt;strong&gt;the business logic&lt;/strong&gt;, being free of any third-party framework and technical implementation. &lt;/p&gt;

&lt;p&gt;As we also use &lt;strong&gt;TDD&lt;/strong&gt; (Test-Driven Development) in our coding process, we thought that applying ideas from hexagonal architecture and TDD would help to produce consistent hexagons covered by tests. This post &lt;strong&gt;shares how we currently implement a hexagon&lt;/strong&gt; in our Node.js back-end. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is how we do it in March 2023. Our practices have evolved for 2 years, and they’re likely to be improved in the future; if it’s the case, we’ll share a digest in a new post ;)&lt;/em&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  The key concepts
&lt;/h2&gt;

&lt;p&gt;In our context, a hexagon targets a specific domain of our app, for instance, the automatic suggestions or the notifications. We enforce to make it self-sufficient and ensure it can be easily enabled or disabled at runtime. Each hexagon contains &lt;strong&gt;4 distinct modules&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Domain&lt;/strong&gt;: Contains the entities and aggregates specific to a domain and the repository interfaces (abstractions) to manipulate these entities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application&lt;/strong&gt;: Contains the services offered by the hexagon. This layer directly manipulates the Domain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt;: Implements the domains’ repository with concrete back-ends such as a database, files, in-memory, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI&lt;/strong&gt;: Handles how the rest of the world interacts with the application (Rest API, CLI, …).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Illustration
&lt;/h2&gt;

&lt;p&gt;Let’s take a concrete example with a hexagon handling the &lt;strong&gt;Knowledge Hexagon&lt;/strong&gt;, the core concept being the &lt;em&gt;BestPractices&lt;/em&gt;, used to raise coding standards from our IDE &amp;amp; Code review extensions. We’ll skip irrelevant details for readability. Note that we’ve still included the folder structures if it can help some readers to understand how to organize their code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain &amp;amp; Infra
&lt;/h3&gt;

&lt;p&gt;First, let’s zoom in on the &lt;strong&gt;Knowledge Hexagon&lt;/strong&gt; on the relationship between the &lt;strong&gt;Domain&lt;/strong&gt; and the &lt;strong&gt;Infra&lt;/strong&gt; layers. In our context, we use a MongoDB implementation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dLHApDtT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architecture-1536x1349.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dLHApDtT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architecture-1536x1349.png" alt="Hexagonal Architecture" width="800" height="703"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The domain is simple and only contains entities and the repositories interfaces. As you can notice, the domain has no link with the Infra layer. We’ve chosen to use a “main” interface &lt;em&gt;KnowledgeRepositories,&lt;/em&gt; that will expose all the repositories of our domain. In the Infra layer, we use &lt;em&gt;Converter&lt;/em&gt; components to transform objects &lt;strong&gt;from Infra to Domain&lt;/strong&gt;, and inversely. This is optional, and it all depends if you rely on an ORM or not. &lt;/p&gt;

&lt;p&gt;Instantiating the Infra Layer looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bpMongoRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BestPracticeRepositoryMongo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;knowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IKnowledgeRepositories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bpMongoRepo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;infra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KnowledgeInfra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeInfra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;knowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// const knowledgeRepositories: IKnowledgeRepositories = new KnowledgeRepositories(new BestPracticeRepositoryinMemory())) would allow to use an in-memory implementation instead&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Application
&lt;/h3&gt;

&lt;p&gt;Still in the &lt;em&gt;Knowledge Hexagon&lt;/em&gt;, Now let’s zoom in on the &lt;strong&gt;Application&lt;/strong&gt; layer and how it interacts with the &lt;strong&gt;Domain&lt;/strong&gt; layer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ueR-f91r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architecture-Application-1536x1046.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ueR-f91r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architecture-Application-1536x1046.png" alt="Hexagonal Architecture - Application" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application will stand as an API, containing &lt;strong&gt;all the services&lt;/strong&gt; the hexagon offers to manipulate the domain, both entities and repositories. As domain repositories in the domain layer are abstractions (e.g., interfaces), they need concrete implementations at runtime. So we can reuse the one instantiated for the Infra layers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bpMongoRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BestPracticeRepositoryMongo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;knowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IKnowledgeRepositories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bpMongoRepo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;knowledgeServices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KnowledgeServices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;knowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  UI (Presentation)
&lt;/h3&gt;

&lt;p&gt;Finally, let’s zoom in on the &lt;strong&gt;UI&lt;/strong&gt; layer, which helps the rest of the world to interact with our hexagon:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IGhwfiWr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architectur-UIe-1536x1127.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IGhwfiWr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architectur-UIe-1536x1127.webp" alt="Hexagonal Architectur - UI" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our context, we have two types of interactions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From our &lt;strong&gt;end-users&lt;/strong&gt; that interact with the app from their IDE/Code review plugins or their web browsers. The express framework is used in this context.&lt;/li&gt;
&lt;li&gt;From other parts of &lt;strong&gt;our API&lt;/strong&gt; (e.g., others hexagons) to avoid re-implementing business logic in a hexagon. We call them &lt;em&gt;InternalExposedMethods&lt;/em&gt;. As we don’t use micro-services in our context, we considered that using such HTTP calls does not make sense. Instead, using these exposed methods works fine and fills our needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The big picture
&lt;/h2&gt;

&lt;p&gt;Finally, if we all put things together, here is the big picture from the macro-level perspective. Again, we’ve included one concept (&lt;em&gt;BestPractice&lt;/em&gt;) from the &lt;em&gt;Knowledge Hexagon&lt;/em&gt;, but we could have added more in this context (such as &lt;em&gt;CodeExample&lt;/em&gt; listed above in the Infra layer).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PzzR1qwS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Big-Picture-1166x1536.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PzzR1qwS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Big-Picture-1166x1536.png" alt="Big Picture.png" width="800" height="1054"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is how the hexagon can be started programmatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeHexagonApp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;//Infra&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bpMongoRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BestPracticeRepositoryMongo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;knowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IKnowledgeRepositories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bpMongoRepo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;infra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KnowledgeInfra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeInfra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;knowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;//Application&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;knowledgeServices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KnowledgeServices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;knowledgeRepositories&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

      &lt;span class="c1"&gt;//UI&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BestPracticeRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;knowledgeServices&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;...];&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exposedMethods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InternalKnowledgeExposedMethods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;knowledgeServices&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can adapt this example to change the infrastructure layer to something different than MongoDB dynamically. If you want to use SQL or in-memory, this could be injected at runtime as a &lt;strong&gt;dependency&lt;/strong&gt; of the &lt;em&gt;KnowledgeHexagonApp&lt;/em&gt; constructor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing tests
&lt;/h2&gt;

&lt;p&gt;Each hexagon embeds a test suite resulting from the TDD practice. For the record, we use &lt;a href="https://www.packmind.com/setup-mocha-in-watch-mode-for-tdd-in-node-js/"&gt;Mocha&lt;/a&gt; and &lt;em&gt;Chai&lt;/em&gt; to write and run our tests. In our context, our tests layer has two main parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first is to test the &lt;strong&gt;Application&lt;/strong&gt; Layer and its functions, using &lt;em&gt;Fake&lt;/em&gt; repositories defined in the Infra folder and using in-memory implementations (basic TypeScript List/Map/…). &lt;/li&gt;
&lt;li&gt;The second targets &lt;strong&gt;our concrete MongoDB implementation&lt;/strong&gt; of the repositories. We’re not testing the Mongoose framework or the MongoDB infrastructure, but we ensure we have the right behavior when interacting with the repositories. It would be a pity to have a bug in production just because we misuse our ORM, right? We use the &lt;a href="https://www.npmjs.com/package/mongo-unit"&gt;mongo-unit&lt;/a&gt; library that runs an embedded in-memory MongoDB server for that purpose. We use hard-coded fixtures in specific files, which mongo-unit will ingest before the &lt;strong&gt;beforeEach&lt;/strong&gt; call.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1BlLs6n5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architecture-Tests-1536x1066.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1BlLs6n5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architecture-Tests-1536x1066.png" alt="Hexagonal Architecture - Tests" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Events management
&lt;/h2&gt;

&lt;p&gt;It does not appear above, but in our API we’ve implemented a custom event management system. We have two requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we want to track core events in our system (a best practice has been created) and record them in our database;&lt;/li&gt;
&lt;li&gt;each hexagon should be able to react to specific events (a user has been deleted)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ve developed a lightweight system that relies on the &lt;a href="https://nodejs.dev/en/learn/the-nodejs-event-emitter/"&gt;EventEmitter&lt;/a&gt; provided by NodeJS. We’ve decided to centralize all our events in a shared module outside hexagons as &lt;em&gt;payload&lt;/em&gt; objects, such as &lt;em&gt;BestPracticeCreatedPayload&lt;/em&gt; emitted when a best practice is created. Here is how it’s implemented in the hexagon:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ckwkyUgT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architecture-Events-2048x1182.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ckwkyUgT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Hexagonal-Architecture-Events-2048x1182.png" alt="Hexagonal Architecture - Events" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;UI layer&lt;/strong&gt;, we can find the &lt;em&gt;Listeners&lt;/em&gt; that react to events emitted by others hexagons in the API. &lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;Application&lt;/strong&gt; layer, the events will be emitted and handled by other hexagons. &lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;Infra&lt;/strong&gt; layer, we implement the services that will perform the event messaging. Instead of using EventEmitter from Node, we could use other alternatives, such as sending a message to a RabbitMQ channel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other discussions
&lt;/h2&gt;

&lt;p&gt;One important point is that &lt;strong&gt;most hexagons use shared concepts&lt;/strong&gt; like &lt;em&gt;BestPractice&lt;/em&gt; or &lt;em&gt;Users&lt;/em&gt;. We voluntarily chose to duplicate their definitions in the Domain and Infra layers. One cool thing with Mongoose is that, when writing the mapping model, we can specify only the fields we need in the hexagon. And if you ask, “&lt;em&gt;what happens when the model evolves ?&lt;/em&gt;”, I’d say this does not happen very often; when it does, only a few hexagons are impacted, so we don’t consider this a main concern for us.&lt;/p&gt;

&lt;p&gt;This version currently fills our need, especially because we’re a &lt;strong&gt;small team,&lt;/strong&gt; and we want each of us to be able to work on any component of the app. We &lt;a href="https://www.packmind.com/community-of-practice-in-software-engineering-teams/"&gt;ban knowledge silos&lt;/a&gt;, and our weekly &lt;a href="https://www.packmind.com/share-best-practices-workshops/"&gt;workshops&lt;/a&gt; to discuss coding standards are helpful. So we’re all responsible for the code, and no one is in charge of a particular domain. So if we radically change how best practices are designed, we can easily discuss this. Our monolith works fine with a single database instance, and if we need in the future to deploy micro-services, we’ve prepared the ground for that. Plus, as we use &lt;strong&gt;TDD, we’ve built a security net&lt;/strong&gt; to prevent possible regressions. &lt;/p&gt;

&lt;p&gt;Finally, our main specificity was to build the &lt;em&gt;ExposedServices&lt;/em&gt; when it made sense for each hexagon. As we run in monolithic approach, we considered a relevant solution. If, in the future, our system evolves and we need to run micro-services, we’ll need to replace the methods calls with class HTTP calls.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Adapt generic concepts in your context
&lt;/h2&gt;

&lt;p&gt;As said earlier, the way we wrote hexagons has evolved and might still evolve. We continuously train our skills on that topic and don’t claim we’re experts in that field (feel free to share your thoughts with us; we’d be happy to take them! :-)).&lt;/p&gt;

&lt;p&gt;To keep our coding standards aligned, we use our platform &lt;a href="https://packmind.com"&gt;Packmind&lt;/a&gt; to share and discuss our best practices. If you also want to define your tailored coding standards, not only on hexagonal architecture, but also on Security, JavaScript, Performance, or whatever topic that matters to you, Packmind might be a good ally for that. &lt;/p&gt;

&lt;p&gt;In a future post, we’ll focus on how we’ve implemented concepts from the &lt;strong&gt;clean&lt;/strong&gt; &lt;strong&gt;architecture in front-end&lt;/strong&gt;, still using TDD, to remain independent as much as possible from the underlying framework (React in our context) and the API.&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>architecture</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Simple knowledge-sharing sabotage field manual</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Thu, 16 Mar 2023 08:16:42 +0000</pubDate>
      <link>https://dev.to/packmind/simple-knowledge-sharing-sabotage-field-manual-50p6</link>
      <guid>https://dev.to/packmind/simple-knowledge-sharing-sabotage-field-manual-50p6</guid>
      <description>&lt;p&gt;In 1944, the OSS — &lt;em&gt;Office of Strategic Services&lt;/em&gt; — of the USA shared with their Europe-based agents a &lt;a href="https://www.openculture.com/2015/12/simple-sabotage-field-manual.html"&gt;sabotage manual&lt;/a&gt; designed to create friction, frustrations, slow-downs, and disturbances in Nazi organizations.&lt;/p&gt;

&lt;p&gt;80 years later, it’s interesting that the guidelines look familiar in many large companies. For instance:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Insist on doing everything through “channels.” Never permit short-cuts to be taken in order to expedite decisions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I recently could have the chance to give a talk at the Bordeaux JS Meetup about how this sabotage manual could be applied to &lt;strong&gt;knowledge sharing&lt;/strong&gt; in tech companies. This post summarizes its content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Our common goal is to harm the company *&lt;strong&gt;&lt;em&gt;Deforest Corp&lt;/em&gt;&lt;/strong&gt;*. They have a bad ecological impact as their primary mission is to massively destroy natural forests to favor intensive agriculture. As a software developer, you’ll join a feature team working on an app used by employees that drive deforestation sites. This app has undergone recent bugs so software quality is a major concern. &lt;/p&gt;

&lt;p&gt;Your mission will be to degrade code quality (or at least, not improve it), increase bugs risks, and negatively impacts the relationships among members in the team. So we choose a smooth, subtle, and (almost) pacific approach. If you’re too radical, you’ll probably be fired immediately, so no interest.&lt;/p&gt;

&lt;p&gt;Your action plan: hurt everything &lt;strong&gt;related to knowledge-sharing&lt;/strong&gt;. Why so? It’s one of the factors that fuels business &lt;a href="https://www.mckinsey.com/industries/technology-media-and-telecommunications/our-insights/developer-velocity-how-software-excellence-fuels-business-performance"&gt;performance&lt;/a&gt;, developers still spend a lot of time &lt;a href="https://survey.stackoverflow.co/2022/"&gt;answering questions&lt;/a&gt; and looking for answers, and knowledge-sharing is still a challenge &lt;a href="https://codingsans.com/state-of-software-development-2020"&gt;for developers&lt;/a&gt;. More generally, it breaks knowledge silos; still need to be convinced of the value?&lt;/p&gt;

&lt;p&gt;Let’s see how to do it?  &lt;/p&gt;

&lt;h2&gt;
  
  
  The guidelines
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Don’t share the &lt;a href="https://www.packmind.com/dantotsu-best-practices/"&gt;root causes&lt;/a&gt; of the bugs you fix&lt;/strong&gt;. You increase the risk that someone else performs the mistake related to the root cause, and the bug will happen again. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don’t share the code improvements you made&lt;/strong&gt;. Any best practice that has a positive impact on the code (readability, performance, …) should be kept for you, preventing others to apply them in their code. Don’t be too greedy about that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don’t update obsolete documentation&lt;/strong&gt;. If you spent a lot of time finding an answer because the Wiki was outdated, ensure your colleagues will also face troubles. Leave it as it is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make yourself unavailable for &lt;a href="https://www.packmind.com/onboarding-developers/"&gt;onboarding sessions&lt;/a&gt;&lt;/strong&gt;. Onboarding new developers is a great exercise for sharing knowledge with a newcomer. Make sure that won’t happen. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don’t read or react to content shared by your colleagues&lt;/strong&gt;. Someone just shared a nice post on Slack? Of course, you’re too busy to read it. But don’t even ask for a short digest, and don’t react at all. They’ll get tired.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Support the idea that aligning your coding standards is pointless&lt;/strong&gt;. Everyone should write code in their own way. YOLO, right? This will bring heterogeneity in the source code, leading to potential quality issues. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decline all pair/mob programming sessions&lt;/strong&gt;. Pair and Mob programming sessions optimize the output while fostering social interactions. You don’t want that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pretend you didn’t see you’ve been asked to do a &lt;a href="https://www.packmind.com/accelerate-code-reviews/"&gt;code review&lt;/a&gt;&lt;/strong&gt;. Oh, you saw this notification for reviewing a pull request? We already received too many notifications, right? So I’m sure you missed that. This will create a good latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postpone the code review by pretending a huge workload&lt;/strong&gt;. Sometimes, you’ll see the notifications. But guess what? You’re too busy, you also have work to do. So wait 2-3 days. And finally, just be honest with your colleague and say “&lt;em&gt;I did my best but unfortunately could find the time. Can you ask to someone else?&lt;/em&gt;” Precious time lost, we love that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate the review without reading the code&lt;/strong&gt;. Free &lt;em&gt;LGTM&lt;/em&gt; distribution at random locations. Don’t take that chance to improve the code, identify possible bugs, or share valuable tips. People will think you did a review. Send code as it is in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suggest conflicting best practices from one review to another&lt;/strong&gt;. You’ve suggested one coding standard the last time? Suggest now the opposite. This will bring confusion, friction, and heterogeneity in the code. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feed endless discussions during code reviews about coding standards&lt;/strong&gt;. GitHub/GitLab provides features to create comment threads, right? Use it as much as you can. This will create latency in the process. And of course, disagree with your interlocutor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make comments on source code NOT updated during the review&lt;/strong&gt;. Run discussions on the code that have not changed at all (you know, these lines of code not starting with “+” or “-” in the diff). Why not? Huge frustration coming in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decline any help coming from someone external to the team.&lt;/strong&gt; 1. A technical coach is about to bring new best practices and methodology to the team? Decline it. We can’t impose a coach, they need your adhesion. Don’t give them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don’t share anything related to your technology watch&lt;/strong&gt;. Did you go to a great Tech conference? Don’t talk about that to your team, don’t share any replay. Don’t talk about some nice blog posts you’ve read. Keep them for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Question the ROI of the &lt;a href="https://www.packmind.com/community-of-practice-in-software-engineering-teams/"&gt;community of practices&lt;/a&gt;&lt;/strong&gt;. Don’t you think it’s strange, these people gathering several times per month, to share common problems and feedback that would be interesting to everyone? They’re just talking, and we have features to implement. Don’t learn from others teams that share common problems with you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensure the company won’t pay for the books read during Book Clubs&lt;/strong&gt;. So that people will be discouraged 1. from participating and thus won’t read that book that still looked interesting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask a lot of questions during Coding Dojos&lt;/strong&gt;. The size of the room, the exercise statements, the schedule, and more. Complain about everything. Ensure this 90min-session won’t be optimized. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Call for BBL boycott&lt;/strong&gt;. Brown-Bag Lunch is scandalous. At that time, everyone should eat alone and not have a chance to learn while sharing a meal. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The summary
&lt;/h2&gt;

&lt;p&gt;Of course, reasoning by absurd is a voluntary choice I made. If knowledge-sharing matters in your context, of course you should consider doing the opposite ;). If some of the guideline remind you some experiences you lived, sorry to hear that and I hope it’s past! &lt;/p&gt;

&lt;h2&gt;
  
  
  What about you?
&lt;/h2&gt;

&lt;p&gt;I’ll end by sharing this &lt;a href="https://www.packmind.com/quizz-evaluate-the-knowledge-sharing-level-in-your-software-engineering-teams/"&gt;3-min test&lt;/a&gt; to evaluate how your current engineering teams are performing in terms of knowledge-sharing, hoping it will give you some insights :)&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>productivity</category>
      <category>codequality</category>
    </item>
    <item>
      <title>How to accelerate your code reviews?</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Tue, 14 Feb 2023 15:47:21 +0000</pubDate>
      <link>https://dev.to/packmind/how-to-accelerate-your-code-reviews-3d4j</link>
      <guid>https://dev.to/packmind/how-to-accelerate-your-code-reviews-3d4j</guid>
      <description>&lt;p&gt;Code reviews through Pull/Merge Requests have become an essential process for the majority of tech companies. A recent &lt;a href="https://media.trustradius.com/product-downloadables/DD/D7/XID8MVZTH0JF.pdf" rel="noopener noreferrer"&gt;study in 2022&lt;/a&gt; unveils that 84% of the surveyed companies use it. Several years of practice allowed practitioners to take a step back on this methodology to identify pain points and how to overcome them. Besides, code reviews should always be continuously evaluated internally to improve how it’s done. In this post, we discuss how to add more &lt;strong&gt;flexibility to the Pull Request process&lt;/strong&gt; and, thus, improve the &lt;strong&gt;delivery time&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;em&gt;&lt;a href="https://cloud.google.com/blog/products/devops-sre/using-the-four-keys-to-measure-your-devops-performance?hl=en" rel="noopener noreferrer"&gt;lead time for change&lt;/a&gt;&lt;/em&gt; is the amount of time it takes a commit to get into production, and is part of the &lt;a href="https://www.packmind.com/what-indicators-of-quality-improvement-of-code/" rel="noopener noreferrer"&gt;4-key metrics&lt;/a&gt; defined by the DevOps Research and Assessment (DORA). Engineering teams seek to optimize this delay to deliver sooner value to their customers. But before bringing solutions, let’s first define the problem: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;During code reviews, what can slow down the whole process, create bottlenecks, and grow the lead time for change?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Packmind's CPO &lt;a href="https://www.linkedin.com/in/ACoAABFKyywBujLtOFyugjDQWMMkon75y4378Ds?lipi=urn%3Ali%3Apage%3Ad_flagship3_company_admin%3ByKJUEF7PSWq5Pdz89BBuSw%3D%3D" rel="noopener noreferrer"&gt;Arthur Magne&lt;/a&gt; recently discussed this topic with &lt;a href="https://www.linkedin.com/in/ACoAAAAORYsBh6CFKKc0gyqQvyGrUGdxdu3-Vro?lipi=urn%3Ali%3Apage%3Ad_flagship3_company_admin%3ByKJUEF7PSWq5Pdz89BBuSw%3D%3D" rel="noopener noreferrer"&gt;Freddy Mallet&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/ACoAAAHvwwABPf_sSqZE6fN_Y5YrrxTnTmC3sdk?lipi=urn%3Ali%3Apage%3Ad_flagship3_company_admin%3ByKJUEF7PSWq5Pdz89BBuSw%3D%3D" rel="noopener noreferrer"&gt;Marcelo Sousa&lt;/a&gt; from Reviewpad during a webinar, and we summarized the main thoughts here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Narrowing the context and purpose of code reviews
&lt;/h2&gt;

&lt;p&gt;The most often quoted obstructions to code reviews are the lack of human resources and the workload of engineers that don’t allow enough time for code reviews. A common reaction consists in adding more human resources to address the issue. Not so fast! &lt;/p&gt;

&lt;p&gt;First ask yourself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Is each code review truly necessary? Can we affirm that all the discussions within reviews are relevant and should happen there?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Indeed, what we observe in practice is that code reviews often lack a &lt;strong&gt;clear context and purpose&lt;/strong&gt;. If you’ve opened a merge/pull request, what do you expect from that? From our point of view, we propose &lt;strong&gt;two primary purposes&lt;/strong&gt; for a Pull Request. &lt;/p&gt;

&lt;h3&gt;
  
  
  #1 Code approval
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I need to ensure my code is okay before merging ⇒ I need your approval&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this case, it may raise friction from both sides, as reviews come late in the process. Authors can feel reviews as a constraint that slows down their delivery, and a frustration to get many comments, with which they won’t always agree. Reviewers can also adopt defensive behavior. What if they think: &lt;em&gt;“I wouldn’t have done [the code] this way. Should I tell this? Should it be blocking for merging? My colleague waits for 2 days; how will my feedback be welcome?”&lt;/em&gt; So you can see that frictions can emerge from code reviews, mainly because we have the &lt;strong&gt;pressure&lt;/strong&gt; induced by the quest for a satisfying &lt;em&gt;lead time for change&lt;/em&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  #2 Get help to improve the code
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I’d like to show you my code and get your feedback to improve it ⇒ I need your help.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Compared with item #1, we’re looking to improve our code and learn from a peer. In this context, it’s worth considering whether this review is part of the delivery process. We may be convinced this code could be merged first. That’s something commonly observed in &lt;a href="https://trunkbaseddevelopment.com/" rel="noopener noreferrer"&gt;trunk-based development&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The workflows and policies are different based on the context of the PR, so it makes sense to define it clearly. &lt;/p&gt;

&lt;p&gt;Another problem we observe during code reviews is the long discussion threads about implementation choices, design, and &lt;strong&gt;best coding practices&lt;/strong&gt;. And there, discussions get emotional and passionate: this is precisely what we want to avoid during reviews. &lt;/p&gt;

&lt;h2&gt;
  
  
  Do we still need code reviews?
&lt;/h2&gt;

&lt;p&gt;Aside from this discussion, you may ask whether doing code reviews still make sense in 2023, in an era where we can find plenty of “DevOps automation” tools on the market.&lt;/p&gt;

&lt;p&gt;We consider that, &lt;strong&gt;yes, indeed&lt;/strong&gt;, code reviews are still necessary. Even though automatic tools have become increasingly powerful, they’re good at &lt;strong&gt;detecting known problems&lt;/strong&gt;. They can’t prove the absence of problems. Think about this Dijkstra quote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Program testing can be used to show the presence of bugs, but never to show their absence!”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So during a Pull Request, we seek for what tools can’t detect. &lt;/p&gt;

&lt;p&gt;Now let’s go back to our main point: how to address the aforementioned issues?&lt;/p&gt;

&lt;h2&gt;
  
  
  Do code reviews only when it makes sense
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The concept of Fluid Pull Request
&lt;/h3&gt;

&lt;p&gt;To answer the question: “&lt;em&gt;Do all Pull Requests require a code review?&lt;/em&gt;”, we can explore the model &lt;a href="https://martinfowler.com/articles/ship-show-ask.html" rel="noopener noreferrer"&gt;Ship Show Ask&lt;/a&gt;. In this approach, PR authors are considered free of trust to evaluate themselves if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code doesn’t require a code review since the changes are trivial (Ship)&lt;/li&gt;
&lt;li&gt;They’d like to show the code changes to colleagues and get their feedback (Show); This mode can sound totally counternatural as the feedback can be provided after the merge. This is part of the paradigm shift.&lt;/li&gt;
&lt;li&gt;The code requires a review (Ask)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So instead of adding more human resources to review the code, we reconsider the necessity for each PR to be approved; This is how we can positively impact the &lt;em&gt;lead time for change&lt;/em&gt;. This concept is also called &lt;a href="https://reviewpad.com/blog/fluid-pull-requests" rel="noopener noreferrer"&gt;Fluid Pull Request&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next generation pull requests with Reviewpad
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://reviewpad.com/" rel="noopener noreferrer"&gt;Reviewpad&lt;/a&gt; is a GitHub app designed to automate your code review process and which implements the Fluid Pull Request concept. A single configuration file in your Git repository will contain all your &lt;strong&gt;workflows&lt;/strong&gt; and &lt;strong&gt;policies&lt;/strong&gt; for your Pull Requests. Based on the context, you’ll define rules to enforce or relax your security net. With Reviewpad, you can define rules such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;If a file in this folder is edited, one person from this group should approve the code.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;If the PR includes a new method in the code with an annotation @Critical, add a label ‘security, and require a double-validation.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rules can decide whether PRs can be automatically merged or refused, define a validation workflow, and more. Rules can address syntactic patterns in the code changes. &lt;/p&gt;

&lt;p&gt;Here is an example of workflow to automatically raise awareness when a critical change is introduced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;api-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reviewpad.com/v3.x&lt;/span&gt;

&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;critical&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Modifications to critical changes&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#294b75"&lt;/span&gt;

&lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;owners&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Group of owners&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;developers&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;["marcelosousa",&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ferreiratiago"]'&lt;/span&gt;    

&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;changes-to-critical-code&lt;/span&gt;
    &lt;span class="na"&gt;always-run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$hasAnnotation("critical")'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$hasFileName("runner.go")'&lt;/span&gt;
    &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$addLabel("critical")'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$assignReviewer($group("owners"),&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1)'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$info("@marcelosousa:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;you&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;are&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;being&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;notified&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;because&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;critical&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;was&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;modified")'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Discuss best practices and design outside code reviews
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Knowledge sharing should be collective
&lt;/h3&gt;

&lt;p&gt;If you request a review to improve your code or show it, this shouldn’t be done under pressure before merging the code. Engineers should instead find dedicated time to discuss code design and best practices, avoiding friction. If you’re having a 1:1 conversation and debating about a best practice, you hold a discussion that &lt;strong&gt;may impact your whole team&lt;/strong&gt;. Indeed, if you come up with a decision, shouldn’t everyone agree with that? We can assume that you seek code uniformity and practice alignment. &lt;/p&gt;

&lt;p&gt;So maybe it’s time to consider running &lt;strong&gt;dedicated workshops&lt;/strong&gt; on your best coding practices, as 1:1 conversations &lt;strong&gt;should not be&lt;/strong&gt; &lt;strong&gt;the right place&lt;/strong&gt; for that purpose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best practices sharing with Packmind
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://packmind.com" rel="noopener noreferrer"&gt;Packmind&lt;/a&gt; is a knowledge-sharing platform for developers and provides integrations with IDE and code reviews (GitHub, GitLab, Azure DevOps, Bitbucket, and Helix Swarm). With the code review plugins, you can create a best coding practice from a comment, and the code is sent to Packmind along with your best practice proposal. You thus avoid long 1:1 discussions during code reviews. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--KGpVUTR8--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_66%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4xhwtql0kvy9m1k1jdt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--KGpVUTR8--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_66%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4xhwtql0kvy9m1k1jdt.gif" alt="https://res.cloudinary.com/practicaldev/image/fetch/s--KGpVUTR8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a4xhwtql0kvy9m1k1jdt.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, Packmind helps your team regularly run &lt;strong&gt;dedicated workshops&lt;/strong&gt; to review contributions from developers (made during code reviews or within IDE). It’s a suitable time to &lt;strong&gt;share knowledge&lt;/strong&gt; and make technical decisions together and ensure everyone is aligned with the appropriate gestures to apply in the code. This is a continuous improvement process for your best coding practices and to grow developers’ skills. &lt;/p&gt;

&lt;h2&gt;
  
  
  Want to accelerate your code reviews?
&lt;/h2&gt;

&lt;p&gt;If you feel your engineering team has bottlenecks in their code reviews, we hope you found in this post some insights to improve your process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consider the necessity to approve each code change;&lt;/li&gt;
&lt;li&gt;Consider dedicated sessions to avoid never-ending discussions during reviews.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also showed that Reviewpad and Packmind can be complementary to accelerate the code reviews while fostering knowledge sharing. &lt;/p&gt;

&lt;p&gt;Tell us if you’ve improved your &lt;strong&gt;lead time for change&lt;/strong&gt; in your context and how you made it; we’d be happy to learn!&lt;/p&gt;

</description>
      <category>career</category>
      <category>discuss</category>
    </item>
    <item>
      <title>33 how-to questions if you develop a JetBrains extension</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Mon, 13 Feb 2023 10:53:00 +0000</pubDate>
      <link>https://dev.to/packmind/33-how-to-questions-if-you-develop-a-jetbrains-extension-5h8o</link>
      <guid>https://dev.to/packmind/33-how-to-questions-if-you-develop-a-jetbrains-extension-5h8o</guid>
      <description>&lt;p&gt;Are you about to start developing a &lt;strong&gt;JetBrains extension&lt;/strong&gt;? Or maybe you’re currently working on that? As you may already know, once you develop a JetBrains extension, it’s available in the marketplace for all the IDEs maintained by the editor, such as JetBrains, PyCharm, Rider, WebStorm, and so on. &lt;/p&gt;

&lt;p&gt;At &lt;a href="https://packmind.com" rel="noopener noreferrer"&gt;Packmind&lt;/a&gt;, we’ve built a JetBrains &lt;a href="https://plugins.jetbrains.com/plugin/15503-promyze" rel="noopener noreferrer"&gt;extension&lt;/a&gt; that helps developers to &lt;a href="https://www.packmind.com/create-own-best-code-practices/" rel="noopener noreferrer"&gt;share their best coding practices&lt;/a&gt; in their organization. We had to dive into the &lt;a href="https://plugins.jetbrains.com/docs/intellij/welcome.html" rel="noopener noreferrer"&gt;JetBrains SDK&lt;/a&gt;, and from that work, we wanted to build a ‘how-to’ list of use cases that might be helpful for you. We wish we had such one when we started working on that extension! Of course, feel free to ask any more questions! 🙂&lt;/p&gt;

&lt;p&gt;NB: We also produced a similar &lt;a href="https://www.promyze.com/21-questions-building-vscode-extension/" rel="noopener noreferrer"&gt;post for VSCode&lt;/a&gt; if you consider a VSCode extension.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;em&gt;All the Java imports have not been included for readability purposes. Still, we added some of them to ensure you’re on the right way ;)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #1 How to access the visible lines in the current editor?
&lt;/h2&gt;

&lt;p&gt;What if you’d be interested in computing stuff only for the content in the visible screen?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;FileEditorManager&lt;/span&gt; &lt;span class="n"&gt;fileEditorManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSelectedTextEditor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
&lt;span class="c1"&gt;// Instantiate the editor above as it suits the most for you&lt;/span&gt;

&lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDocument&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="n"&gt;visibleArea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVisibleArea&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;startLine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLineNumber&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visibleArea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;endLine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLineNumber&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visibleArea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;visibleArea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;startLine&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;endLine&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;startOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLineStartOffset&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;endOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLineEndOffset&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lineText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startOffset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endOffset&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;//Do smth with it, add to a list, or concatenate to a string.&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #2 How to get the selected text?
&lt;/h2&gt;

&lt;p&gt;Here're two examples of how to get the selected text in the editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getSelectedTextEditor&lt;/span&gt;&lt;span class="o"&gt;();;&lt;/span&gt;
&lt;span class="nc"&gt;SelectionModel&lt;/span&gt; &lt;span class="n"&gt;selectionModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSelectionModel&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selectionModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasSelection&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;selectedText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectionModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSelectedText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Alternative&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selectionModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasSelection&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectionModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSelectionStart&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selectionModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSelectionEnd&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;selectedText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDocument&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #3 How to add a marker to a line with a custom image?
&lt;/h2&gt;

&lt;p&gt;You’ll need to extend the &lt;strong&gt;&lt;code&gt;GutterIconRenderer&lt;/code&gt;&lt;/strong&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.editor.markup.GutterIconRenderer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lineNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...;&lt;/span&gt; &lt;span class="c1"&gt;// the line number where you want to add a gutter&lt;/span&gt;

&lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;IconLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIcon&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/icons/youricon.png"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;GutterIconRenderer&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GutterIconRenderer&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="nf"&gt;getIcon&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;GutterIconRenderer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;GutterIconRenderer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getIcon&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;};&lt;/span&gt;

&lt;span class="nc"&gt;EditorGutter&lt;/span&gt; &lt;span class="n"&gt;gutter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;EditorEx&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getGutter&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;gutter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerTextAnnotation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lineNumber&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Override the &lt;strong&gt;&lt;code&gt;equals&lt;/code&gt;&lt;/strong&gt; method ensures that the marker won't be duplicated when the line is repainted.&lt;/p&gt;

&lt;h2&gt;
  
  
  #4 How to get the programming language of the current editor?
&lt;/h2&gt;

&lt;p&gt;Easy one when you have access to the current Document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.fileTypes.FileType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;...;&lt;/span&gt;
&lt;span class="nc"&gt;FileType&lt;/span&gt; &lt;span class="n"&gt;fileType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;EditorEx&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getDocument&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getFileType&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fileType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #5 How to add a menu on the right-click event?
&lt;/h2&gt;

&lt;p&gt;To add a menu to the right-click event, you need to create a custom &lt;strong&gt;&lt;code&gt;AnAction&lt;/code&gt;&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.actionSystem.AnAction&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//... &lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyMenuAction&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AnAction&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyMenuAction&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"My Menu Action"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;actionPerformed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnActionEvent&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Your implementation here&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And register it as a popup menu action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.actionSystem.ActionManager&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="nc"&gt;ActionManager&lt;/span&gt; &lt;span class="n"&gt;actionManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ActionManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;actionManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerAction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myMenuActionId"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyMenuAction&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #6 How to set a custom shortcut to perform an action?
&lt;/h2&gt;

&lt;p&gt;Following tip #5, declare first an &lt;strong&gt;&lt;code&gt;AnAction&lt;/code&gt;&lt;/strong&gt; class. Then we will use the  &lt;strong&gt;&lt;code&gt;Keymap&lt;/code&gt;&lt;/strong&gt; class to add a shortcut to the action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.keymap.Keymap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//....&lt;/span&gt;
&lt;span class="nc"&gt;Keymap&lt;/span&gt; &lt;span class="n"&gt;keymap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KeymapManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getActiveKeymap&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;actionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"myActionId"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;MyAction&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyAction&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addShortcut&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actionId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;KeyStroke&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKeyStroke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KeyEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VK_1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InputEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CTRL_DOWN_MASK&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Ctrl+1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #7 How to list the JetBrains extensions pane opened in the IDE?
&lt;/h2&gt;

&lt;p&gt;If your extension needs to know that information, here you are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.wm.ToolWindowManager&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="nc"&gt;ToolWindowManager&lt;/span&gt; &lt;span class="n"&gt;toolWindowManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ToolWindowManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;toolWindowManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getToolWindowIds&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ToolWindow&lt;/span&gt; &lt;span class="n"&gt;toolWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;toolWindowManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getToolWindow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toolWindow&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;toolWindow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isVisible&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Opened tool window: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;&lt;code&gt;isVisible&lt;/code&gt;&lt;/strong&gt; method determines if the tool window is currently open.&lt;/p&gt;

&lt;h2&gt;
  
  
  #8 How to retrieve all the JetBrains extensions installed?
&lt;/h2&gt;

&lt;p&gt;This information can be complementary to the previous tip #7:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.extensions.ExtensionPoint&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="nc"&gt;ExtensionPoint&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PluginDescriptor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;extensionPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Extensions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRootArea&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getExtensionPoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Extensions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getExtensionPointName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.intellij.pluginsList"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PluginDescriptor&lt;/span&gt; &lt;span class="n"&gt;pluginDescriptor&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;extensionPoint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getExtensionList&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Installed plugin: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pluginDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #9 How to underline a line of code?
&lt;/h2&gt;

&lt;p&gt;You can use the &lt;strong&gt;&lt;code&gt;EditorGutterComponent&lt;/code&gt;&lt;/strong&gt; class and the &lt;strong&gt;&lt;code&gt;GutterIconRenderer&lt;/code&gt;&lt;/strong&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.editor.markup.GutterIconRenderer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.codeInsight.daemon.LineMarkerInfo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyLineMarkerProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;LineMarkerProvider&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;LineMarkerInfo&lt;/span&gt; &lt;span class="nf"&gt;getLineMarkerInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;PsiElement&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;PsiMethodCallExpression&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;startOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTextRange&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getStartOffset&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;endOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTextRange&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getEndOffset&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;TextRange&lt;/span&gt; &lt;span class="n"&gt;textRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startOffset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endOffset&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;GutterIconRenderer&lt;/span&gt; &lt;span class="n"&gt;gutterIconRenderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyGutterIconRenderer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LineMarkerInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;textRange&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Pass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UPDATE_ALL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gutterIconRenderer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;GutterIconRenderer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Alignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RIGHT&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is the &lt;em&gt;GutterIconRenderer&lt;/em&gt; implementation, where we took as an example the notification icon, but you’ll be welcome to add your icon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyGutterIconRenderer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;GutterIconRenderer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="nf"&gt;getIcon&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;AllIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Ide&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Info&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #10 How to retrieve the file name of the current tab?
&lt;/h2&gt;

&lt;p&gt;Here you are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.vfs.VirtualFile&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="nc"&gt;FileEditorManager&lt;/span&gt; &lt;span class="n"&gt;fileEditorManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSelectedTextEditor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;VirtualFile&lt;/span&gt; &lt;span class="n"&gt;virtualFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManagerEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstanceEx&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;virtualFile&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Current file name: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;virtualFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the &lt;strong&gt;&lt;code&gt;FileEditorManagerEx&lt;/code&gt;&lt;/strong&gt; class provides additional functionality for managing editor tabs. &lt;/p&gt;

&lt;h2&gt;
  
  
  #11 How to listen when a tab has been closed?
&lt;/h2&gt;

&lt;p&gt;You can implement a listener for when a tab is closed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;addFileEditorManagerListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManagerListener&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fileClosed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManager&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;VirtualFile&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"File closed: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #12 How to listen when a tab has been opened?
&lt;/h2&gt;

&lt;p&gt;In the same spirit as tip #11:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;addFileEditorManagerListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManagerListener&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fileOpened&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManager&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;VirtualFile&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"File opened: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #13 How to listen when the current tab has changed?
&lt;/h2&gt;

&lt;p&gt;Again, same approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;addFileEditorManagerListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManagerListener&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;selectionChanged&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManagerEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;VirtualFile&lt;/span&gt; &lt;span class="n"&gt;newFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNewFile&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newFile&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Current tab changed to: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;newFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #14 How to add and access a JetBrains extension setting?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;Settings&lt;/code&gt;&lt;/strong&gt; class and the &lt;strong&gt;&lt;code&gt;State&lt;/code&gt;&lt;/strong&gt; class will help you. In our case in Promyze, we had to use the current user API Key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PromyzeSettings&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;SETTING_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"promyzeApiKey"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@State&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SETTING_KEY&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;storages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nd"&gt;@Storage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"promyzeSettings.xml"&lt;/span&gt;&lt;span class="o"&gt;)})&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PromyzeSettingState&lt;/span&gt; &lt;span class="n"&gt;settingState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PromyzeSettingState&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PromyzeSettingState&lt;/span&gt; &lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ServiceManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySettings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;settingState&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PromyzeSettingState&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;promyzeApiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To access the setting, you can use the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;userApiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PromyzeSettings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;promyzeApiKey&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #15 How to implement a Caret Listener?
&lt;/h2&gt;

&lt;p&gt;This is useful if your extension needs to run an analysis when the caret moves. The &lt;strong&gt;&lt;code&gt;CaretListener&lt;/code&gt;&lt;/strong&gt; interface will be your alley:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.editor.CaretListener&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getSelectedTextEditor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;CaretModel&lt;/span&gt; &lt;span class="n"&gt;caretModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCaretModel&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;caretModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addCaretListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CaretListener&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;caretPositionChanged&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CaretEvent&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Caret position changed: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNewPosition&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;&lt;code&gt;getNewPosition&lt;/code&gt;&lt;/strong&gt; method of the &lt;strong&gt;&lt;code&gt;CaretEvent&lt;/code&gt;&lt;/strong&gt; class returns the new position of the caret.&lt;/p&gt;

&lt;h2&gt;
  
  
  #16 How to get the current line of the caret?
&lt;/h2&gt;

&lt;p&gt;Here you are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getSelectedTextEditor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;CaretModel&lt;/span&gt; &lt;span class="n"&gt;caretModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCaretModel&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lineNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDocument&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getLineNumber&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;caretModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOffset&lt;/span&gt;&lt;span class="o"&gt;());.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #17 How to listen when the current editor is saved?
&lt;/h2&gt;

&lt;p&gt;You’ll need to add a listener:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getSelectedTextEditor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDocument&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addDocumentListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DocumentListener&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;beforeDocumentChange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DocumentEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Called before the text of the document is changed.&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;documentChanged&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DocumentEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Called after the text of the document has been changed.&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #18 How to listen when a specific shortcut is called?
&lt;/h2&gt;

&lt;p&gt;This is how you can listen to the keyboard shortcut &lt;strong&gt;CTRL + X.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.actionSystem.KeyboardShortcut&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="nc"&gt;KeyboardShortcut&lt;/span&gt; &lt;span class="n"&gt;keyboardShortcut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KeyboardShortcut&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KeyStroke&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKeyStroke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KeyEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VK_X&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InputEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CTRL_DOWN_MASK&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;AnAction&lt;/span&gt; &lt;span class="n"&gt;anAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AnAction&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;actionPerformed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnActionEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// handle shortcut event&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;anAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerCustomShortcutSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomShortcutSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyboardShortcut&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CommonDataKeys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;EDITOR_COMPONENT&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #19 How to change the logo of my JetBrains extension?
&lt;/h2&gt;

&lt;p&gt;Add your icon to the &lt;strong&gt;&lt;code&gt;resources&lt;/code&gt;&lt;/strong&gt; directory of the project (in one of the following formats: &lt;strong&gt;&lt;code&gt;.png&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;.jpeg&lt;/code&gt;&lt;/strong&gt;, or &lt;strong&gt;&lt;code&gt;.gif)&lt;/code&gt;.&lt;/strong&gt; Next, in the &lt;strong&gt;&lt;code&gt;plugin.xml&lt;/code&gt;&lt;/strong&gt; file, you need to specify the path to the image file in the &lt;strong&gt;&lt;code&gt;icon&lt;/code&gt;&lt;/strong&gt; attribute of the &lt;strong&gt;&lt;code&gt;idea-plugin&lt;/code&gt;&lt;/strong&gt; tag like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;idea-plugin&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;icon&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"icon.png"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/idea-plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #20 How can I display a modal form after a command is sent from a right-click menu?
&lt;/h2&gt;

&lt;p&gt;Assuming you’ve implemented an action in the contextual menu, you can then  display a modal form thanks to the*&lt;em&gt;&lt;code&gt;DialogWrapper&lt;/code&gt;&lt;/em&gt;* class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAction&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AnAction&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;actionPerformed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnActionEvent&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;MyDialog&lt;/span&gt; &lt;span class="n"&gt;dialog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyDialog&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProject&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;dialog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;show&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyDialog&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;DialogWrapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyDialog&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Project&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;setTitle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"My Dialog"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Nullable&lt;/span&gt;
  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="nc"&gt;JComponent&lt;/span&gt; &lt;span class="nf"&gt;createCenterPanel&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;JPanel&lt;/span&gt; &lt;span class="n"&gt;panel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JPanel&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Add components to the panel here&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;panel&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #21 How to prompt a warning notification?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;Notification&lt;/code&gt;&lt;/strong&gt; class will help you with that purpose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.intellij.notification.Notification;
//...
Notification notification = new Notification("MyGroup", "My Title", "My Content", NotificationType.WARNING);
Notifications.Bus.notify(notification, project);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the Notification object, you can also set the &lt;strong&gt;&lt;code&gt;setListener&lt;/code&gt;&lt;/strong&gt; property to provide a listener that will be notified when the notification is clicked. &lt;/p&gt;

&lt;p&gt;You can use as well NotificationType.INFO and NotificationType.ERROR for informative and error messages. &lt;/p&gt;

&lt;h2&gt;
  
  
  #22 How to get the IDE name?
&lt;/h2&gt;

&lt;p&gt;As said earlier, this value can be "IntelliJ IDEA", "PyCharm", "WebStorm", etc., depending on the product being used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.application.ApplicationInfo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="c1"&gt;//...**&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;ideName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApplicationInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getFullProductName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #23 How to get the current version of the IDE?
&lt;/h2&gt;

&lt;p&gt;Related to tip #22:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;ideVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApplicationInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getFullVersion&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full version string typically has the format "major.minor.build".&lt;/p&gt;

&lt;h2&gt;
  
  
  #24 How to get the current compilation issues in the opened file?
&lt;/h2&gt;

&lt;p&gt;In case your extension needs them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.codeInspection.ex.HighlightManager*&lt;/span&gt;&lt;span class="o"&gt;*;&lt;/span&gt;
&lt;span class="c1"&gt;//...**&lt;/span&gt;
&lt;span class="nc"&gt;FileEditorManager&lt;/span&gt; &lt;span class="n"&gt;fileEditorManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fileEditorManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSelectedTextEditor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDocument&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;PsiFile&lt;/span&gt; &lt;span class="n"&gt;psiFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PsiDocumentManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getPsiFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psiFile&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProblemDescriptor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;problems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;GlobalInspectionContext&lt;/span&gt; &lt;span class="n"&gt;globalContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InspectionManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;createNewGlobalContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InspectionToolWrapper&lt;/span&gt; &lt;span class="nl"&gt;toolWrapper:&lt;/span&gt; &lt;span class="n"&gt;globalContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInspectionTools&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psiFile&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;ProblemsHolder&lt;/span&gt; &lt;span class="n"&gt;problemsHolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProblemsHolder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InspectionManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;toolWrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;psiFile&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;problemsHolder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;globalContext&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;problemsHolder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResults&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getResultItems&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Do something with the problems list&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #25 How to get the content of the Output Tab?
&lt;/h2&gt;

&lt;p&gt;To retrieve the output content of the app, you can use this trick:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.wm.ToolWindow*&lt;/span&gt;&lt;span class="o"&gt;*;&lt;/span&gt;
&lt;span class="c1"&gt;//...**&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;outputContent&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;ToolWindow&lt;/span&gt; &lt;span class="n"&gt;toolWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ToolWindowManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getToolWindow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Output"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toolWindow&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Content&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;toolWindow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getContentManager&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getContent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;JComponent&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getComponent&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;JTextArea&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;JTextArea&lt;/span&gt; &lt;span class="n"&gt;textArea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JTextArea&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;outputContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;textArea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the tab name is dynamic so you can retrieve the content for another tab.&lt;/p&gt;

&lt;h2&gt;
  
  
  #26 How to get the current editor theme?
&lt;/h2&gt;

&lt;p&gt;It might impact the way you want to render your components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.editor.colors.EditorColorsManager*&lt;/span&gt;&lt;span class="o"&gt;*;**&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="nc"&gt;EditorColorsManager&lt;/span&gt; &lt;span class="n"&gt;editorColorsManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EditorColorsManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;EditorColorsScheme&lt;/span&gt; &lt;span class="n"&gt;currentScheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editorColorsManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getGlobalScheme&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;themeName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentScheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #27 How to listen when the IDE is opened?
&lt;/h2&gt;

&lt;p&gt;You must create a class that implements &lt;strong&gt;&lt;code&gt;StartupActivity&lt;/code&gt;&lt;/strong&gt; and add it as an extension in your plugin.xml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.startup.StartupActivity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyStartupActivity&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;StartupActivity&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;runActivity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;Project&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// your code here, it will be executed when the IDE is opened&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in your plugin.xml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;extensions&lt;/span&gt; &lt;span class="na"&gt;defaultExtensionNs=&lt;/span&gt;&lt;span class="s"&gt;"com.intellij"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;startupActivity&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;&lt;span class="s"&gt;"your.package.MyStartupActivity"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #28 How to listen when the IDE is closed?
&lt;/h2&gt;

&lt;p&gt;Similar to tip #27:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApplicationListener&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ApplicationListener&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;beforeApplicationQuit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;isRestart&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// your code here, it will be executed before the IDE is closed&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in the plugin.xml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;extensions&lt;/span&gt; &lt;span class="na"&gt;defaultExtensionNs=&lt;/span&gt;&lt;span class="s"&gt;"com.intellij"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;applicationListener&lt;/span&gt; &lt;span class="na"&gt;implementation=&lt;/span&gt;&lt;span class="s"&gt;"your.package.MyApplicationListener"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/extensions&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #29 How to run an asynchronous task in background?
&lt;/h2&gt;

&lt;p&gt;This is recommended to avoid blocking operations for the users. You can be sure they won’t hesitate to uninstall your extension if it’s too annoying ;) &lt;/p&gt;

&lt;p&gt;You can create a class that extends &lt;strong&gt;&lt;code&gt;Task.Backgroundable&lt;/code&gt;&lt;/strong&gt; and override the &lt;strong&gt;&lt;code&gt;run&lt;/code&gt;&lt;/strong&gt; method to perform the task in the background. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.task.Task.Backgroundable&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//... &lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyBackgroundTask&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Backgroundable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyBackgroundTask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nullable&lt;/span&gt; &lt;span class="nc"&gt;Project&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="nc"&gt;ProgressIndicator&lt;/span&gt; &lt;span class="n"&gt;progressIndicator&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// your code here, it will be executed in the background&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;MyBackgroundTask&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyBackgroundTask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"My Background Task"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;ProgressManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #30 How to get the current language of the IDE?
&lt;/h2&gt;

&lt;p&gt;Here you are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Locale&lt;/span&gt; &lt;span class="n"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDefault&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The language code of the locale by using the &lt;strong&gt;&lt;code&gt;getLanguage()&lt;/code&gt;&lt;/strong&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLanguage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #31 How to listen when an application is run?
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;Run&lt;/em&gt; feature in your IDE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.application.ApplicationListener&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.application.ApplicationManager&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApplicationListener&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ApplicationListener&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ApplicationManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getApplication&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;addApplicationListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;applicationStarted&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// your code here, executed when the application starts&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #32 How to listen when an &lt;em&gt;Extract Method&lt;/em&gt; operation is called?
&lt;/h2&gt;

&lt;p&gt;You can also listen for specific code operations; here, we take the &lt;em&gt;Extract Method&lt;/em&gt; operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.refactoring.RefactoringEventListener&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.refactoring.RefactoringEventData&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyRefactoringEventListener&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RefactoringEventListener&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;RefactoringEventListener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DEFAULT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;refactoringStarted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;refactoringId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RefactoringEventData&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;refactoringId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Extract Method"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// your code here, executed when the Extract Method operation is called&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #33 How to know if the current editor has defined the "LF" or "CRLF" mode for line breaks?
&lt;/h2&gt;

&lt;p&gt;For the record, LF is more on Unix/Mac, while CRLF is used on Windows. Trust me, if you need to parse the source code, it can spare you some trouble ;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EditorHelper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCurrentEditor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDocument&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lineSeparator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LINE_SEPARATOR_KEY&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lineSeparator&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Lf mode"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\r\n"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lineSeparator&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"crlf mode"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;That’s all, folks! We hope it can help you start working on your JetBrains extension. In case you work with your team, it can make sense to define best practices when developing a JetBrains extension. Packmind can help you with that; feel free &lt;a href="https://packmind.com" rel="noopener noreferrer"&gt;to try it&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>extensions</category>
    </item>
    <item>
      <title>Writing clean code in Python</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Wed, 08 Feb 2023 08:46:54 +0000</pubDate>
      <link>https://dev.to/packmind/writing-clean-code-in-python-423f</link>
      <guid>https://dev.to/packmind/writing-clean-code-in-python-423f</guid>
      <description>&lt;p&gt;Python is a programming language that offers a high level of flexibility. The counterpart is that developers can easily use different tricks that will lead to heterogeneity in the source code, decreasing its readability and maintainability. As with any programming language, it’s important to &lt;a href="https://www.packmind.com/create-best-coding-practices/"&gt;define best practices&lt;/a&gt; in a team to bring consistency to the source code, avoid bugs, and save time during &lt;a href="https://packmind.com/save-time-during-your-code-reviews-on-github/"&gt;code reviews&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://packmind.com"&gt;Packmind&lt;/a&gt;, we recently ran a webinar with our partner &lt;a href="https://arolla.fr"&gt;Arolla&lt;/a&gt; (the replay is &lt;a href="https://www.youtube.com/watch?v=Zb1E6V1cbTM&amp;amp;ab_channel=ProMyze"&gt;in French&lt;/a&gt;) on &lt;em&gt;How to write clean code in Python?&lt;/em&gt; We share in this post an extract of the discussed practices.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NB: Please note that we don’t claim the following practices are always valid, and the “don’t” examples are always bad. Trust yourself ;)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #1 Use Counter to count occurrences
&lt;/h3&gt;

&lt;p&gt;Using the Counter from the &lt;code&gt;collection&lt;/code&gt; library is more efficient at run time when you want to count different occurrences of elements in a list, tuple, or another hashable iterable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;
&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Will print =&amp;gt; Counter({2: 5, 3: 4, 1: 3, 4: 2, 5: 1})
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #2 Use "in" to simplify if statements
&lt;/h3&gt;

&lt;p&gt;The keyword “&lt;em&gt;in”&lt;/em&gt; is an elegant, readable and maintainable way to check the presence of a specific element in a sequence :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;detectives&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sherlock Holmes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hercule Poirot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Batman&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Batman&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Don't
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Batman&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hercule Poirot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sherlock Holmes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;That person is a detective&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Do 
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;detectives&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;That person is a detective&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #3 Put actual before expected in assertions
&lt;/h3&gt;

&lt;p&gt;Assertions will be easier to read in this order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_big_stuff&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;actual_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;expected_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;actual_result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expected_result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #4 &lt;strong&gt;Use properties when relevant&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Sometimes, when we create a class, we will have a field whose value stems from one or multiple other ones. For example, in a class &lt;em&gt;Person&lt;/em&gt;, we can have a &lt;code&gt;full_name&lt;/code&gt; field which concatenates the values of &lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;In such cases, it is important to protect the content of the composite field by defining a property with the annotation &lt;em&gt;@property&lt;/em&gt;. Going back to our example with the class &lt;em&gt;Person&lt;/em&gt;, this will prevent a user to set the value of the &lt;code&gt;full_name&lt;/code&gt; from outsite by writing &lt;code&gt;person.full_name = ...&lt;/code&gt; .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;last_name&lt;/span&gt;

      &lt;span class="nd"&gt;@property&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;full_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #5 Use fully qualified, absolute imports
&lt;/h3&gt;

&lt;p&gt;This makes the code more readable and maintainable, so that when it’s time to modify the code, it is easier to figure where each object in the code comes from.&lt;/p&gt;

&lt;p&gt;Performance-wise, it is basically the same as importing the full module (ex. &lt;code&gt;import foo&lt;/code&gt; ) as Python always loads the full module, whether or not we import just an object of that module.&lt;/p&gt;

&lt;p&gt;That is to say if when we write &lt;code&gt;from foo.bar import Bar&lt;/code&gt; , Python loads the entirety of the module &lt;code&gt;foo.bar&lt;/code&gt; and then proceeds to pick &lt;code&gt;Bar&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;foo.bar&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Bar&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;spam.eggs&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Eggs&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;eggs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Eggs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #6 Use iterators instead of explicit lists
&lt;/h3&gt;

&lt;p&gt;Avoid creating a new list when it’s not relevant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_max&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;iterable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bbb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;# Don't
&lt;/span&gt;    &lt;span class="n"&gt;max_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="c1"&gt;# Do
&lt;/span&gt;      &lt;span class="n"&gt;max_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;max_len&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;

&lt;span class="nf"&gt;get_max&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #7 Use list comprehensions
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;&lt;em&gt;list comprehension&lt;/em&gt;&lt;/strong&gt; is a way of creating a new list by transforming elements from an existing iterable (such as a list, tuple, or dictionary), and we want to, filter some elements, and perform operations on each element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Don't
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_even_nums_squared&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;

&lt;span class="c1"&gt;# Do
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_even_nums_squared&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;#8 Prefer using keyword-only arguments&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Many times, especially when there is no logical order between the parameters of a function or method, it is recommended to call the function or method by specifying the name of the parameters (ex. &lt;code&gt;make_coffee(with_sugar=True, with_milk=True)&lt;/code&gt; ). &lt;/p&gt;

&lt;p&gt;It is possible to force the parameters to be named when the function/method is called. We can do that by using the “*”  at the beginning of the parameters.&lt;/p&gt;

&lt;p&gt;This avoids many possible issues and confusion.&lt;/p&gt;

&lt;p&gt;However, it is not something to do all the time but rather when it makes sense.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_coffee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with_sugar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with_milk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="nf"&gt;make_coffee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’d prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_coffee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with_sugar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with_milk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="nf"&gt;make_coffee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with_milk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with_sugar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #9 Use ABCMeta for abstract classes
&lt;/h3&gt;

&lt;p&gt;This practice can be relevant if you work with developers who are not expert in Python, but are more familiar with Java or C#. They’ll be more comfortable with the “abstract” concepts for classes and methods. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;ABCMeta&lt;/code&gt;&lt;/strong&gt; is a metaclass (a class that creates classes) in Python. It stands for "Abstract Base Class Meta".&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Fooer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;NotImplementedError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Spam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Fooer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spamming&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’d prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;abc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ABCMeta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;abstractmethod&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Fooer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metaclass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ABCMeta&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Spam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Fooer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spamming foos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #10 Use a main() function
&lt;/h3&gt;

&lt;p&gt;Avoid global variables and, in general, source code outside functions.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;

&lt;span class="n"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;

&lt;span class="n"&gt;SERVER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’d prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;host&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;

    &lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #11 &lt;strong&gt;Do not use empty lists as default arguments&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This can lead to unexpected and very weird behavior.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_player_to_team&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;team&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt;
    &lt;span class="n"&gt;team&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;team&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’d prefer::&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_player_to_team&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;team&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;team&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="n"&gt;team&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;team&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #12 &lt;strong&gt;Prefer f-strings to string concatenation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;F-strings allow writing sentences in a far more natural (and admittedly less annoying) way than what string concatenation can provide.&lt;/p&gt;

&lt;p&gt;Do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Jake&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;

&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; years old now&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Jake&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;

&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; is &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; years old now&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #13 &lt;strong&gt;Prefer enumerate() to range(len()) when you want keep the index of iterable items&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This practice contributes to code readability as well as its performance while still keeping the index around. The performance gain is because &lt;em&gt;enumerate()&lt;/em&gt; creates an iterator for the collection, which is more efficient than looping through each item&lt;/p&gt;

&lt;p&gt;Don’t:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ages&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m client n°&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; and I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; years old, I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m an adult now.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ages&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m client n°&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; and I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; years old, I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m an adult now.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All these best practices can be defined in Packmind from our IDE and Code reviews plugins. We’re compatible with VSCode, JetBrains suite, and Eclipse. So if you code Python with VSCode or PyCharm, you can go for it! Each practice you create will then be validated as a team during dedicated workshops, and the final result looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P-1OaW0Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Untitled-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P-1OaW0Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Untitled-8.png" alt="An example of best practice in Packmind" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can provide syntactic patterns to provide suggestions while coding or reviewing code and use this practice during onboarding workshops in Packmind.&lt;/p&gt;

&lt;p&gt;The whole catalog is also available on our public &lt;a href="https://bestcodingpractices.dev/catalog/63e0d7b2498b45115fbb18cb"&gt;Hub of best practices&lt;/a&gt;, where users can share practices on various domains and use them in Packmind.&lt;/p&gt;

&lt;p&gt;You can start creating your practices now &lt;a href="https://packmind.com"&gt;for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>productivity</category>
      <category>codequality</category>
    </item>
    <item>
      <title>20 knowledge types and information sources for developers</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Fri, 03 Feb 2023 10:19:29 +0000</pubDate>
      <link>https://dev.to/packmind/20-knowledge-types-and-information-sources-for-developers-32ll</link>
      <guid>https://dev.to/packmind/20-knowledge-types-and-information-sources-for-developers-32ll</guid>
      <description>&lt;p&gt;In a previous post, we bootstrapped &lt;a href="https://www.packmind.com/knowledge-management-and-tools-for-software-developers/" rel="noopener noreferrer"&gt;some thoughts&lt;/a&gt; about what knowledge was useful for developers in their work. Also, we discussed that each piece of knowledge has its specificities (when and how it’s hit, how often it’s updated, how critical it is to notify the audience, …).   &lt;/p&gt;

&lt;p&gt;In this post, we propose a cartography of 20 &lt;strong&gt;different types of knowledge and information sources&lt;/strong&gt; that developers &lt;strong&gt;interact&lt;/strong&gt; with during their work. This might help you structure your team’s &lt;a href="https://www.packmind.com/onboarding-developers-best-coding-practices/" rel="noopener noreferrer"&gt;onboarding&lt;/a&gt; process of new developers and ensure they have access to the data they need to succeed. Or, if you just joined a new company, you can use it as a checklist to see if you’ve got all the access you need. This isn’t exhaustive, and you may identify more knowledge sources — Let us know! Also, we list a few examples of tools; some more exist.&lt;/p&gt;

&lt;h3&gt;
  
  
  #1 The &lt;em&gt;How-to&lt;/em&gt; procedures, tutorials, and &lt;em&gt;Get started&lt;/em&gt; guides
&lt;/h3&gt;

&lt;p&gt;Helpful for setting up software or project on a laptop, when configuring your IDE for the first time, when we need to connect to a remote database, bootstrapping a new project according to a specific skeleton, or how to ship a new version of the app. A small group maintains this documentation, which is often a one-time read procedure, as you won’t need it every day. But we’re happy to have it when we need it. We also call them &lt;em&gt;evergreen&lt;/em&gt; content. &lt;em&gt;Tools&lt;/em&gt;: Confluence, Notion.&lt;/p&gt;

&lt;h3&gt;
  
  
  #2 Best coding practices
&lt;/h3&gt;

&lt;p&gt;Developers’ gestures in writing source code according to the team practices. This is about properly writing the source code in the developer’s context. These best practices should be precisely defined in a team and at the company level, continuously maintained, and regularly discussed. Integration during code reviews and in the IDE are a must-have. &lt;em&gt;Tools&lt;/em&gt;: &lt;a href="https://packmind.com" rel="noopener noreferrer"&gt;Packmind&lt;/a&gt;. &lt;/p&gt;




&lt;p&gt;&lt;a href="https://packmind.com" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.promyze.com%2Fwp-content%2Fuploads%2FSans-titre-1536x347.jpg" alt="packmind" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  #3 Code documentation
&lt;/h3&gt;

&lt;p&gt;Get insights on the code base, a sub-part, or a particular code snippet. It can help to understand complex behavior, a past non-intuitive technical choice, or an implementation detail that needs explanations. Use it carefully, as it’s best practice to have a self-explanatory code where comments don’t bring value. This code documentation is usually contextual, and developers should keep it up-to-date. &lt;em&gt;Tools&lt;/em&gt;: Swimm, Read the Docs.  &lt;/p&gt;

&lt;h3&gt;
  
  
  #4 Tests suites
&lt;/h3&gt;

&lt;p&gt;Test code is a powerful documentation of the code, and we could quote it in the previous bullet #3. Reading test code gives an overview of the core methods of your software and gives concrete examples of usage, especially if your team writes tests using the Given/When/Then or Arrange/Act/Assert patterns. If you dive into a new module, looking for tests is a great start to becoming more familiar with the code base. &lt;em&gt;Tools&lt;/em&gt;: your favorite test framework, JUnit, Mocha, PyTest. &lt;/p&gt;

&lt;h3&gt;
  
  
  #5 API Documentation
&lt;/h3&gt;

&lt;p&gt;An unavoidable one, it helps you understand how to use an SDK or an API, discover the available services and their purpose, and how to interact with them programmatically. The code examples give you confidence in using the API and handling situations when errors happen. At first glance, you should detect whether or not the API satisfies your needs. Otherwise, go your way. &lt;em&gt;Tools&lt;/em&gt;: Swagger, Doxygen, apiDoc, Readme. &lt;/p&gt;

&lt;h3&gt;
  
  
  #6 The code quality issues
&lt;/h3&gt;

&lt;p&gt;Check if the source code contains security issues, bad smells, formatting troubles, readability improvements, and more, with source code static analysis. You can have feedback on your IDE during a code review and a global overview in a dedicated dashboard. These linters are available for all programming languages and help keep the code syntax consistent. &lt;em&gt;Tools&lt;/em&gt;: SonarQube, Codiga, EsLint.&lt;/p&gt;

&lt;h3&gt;
  
  
  #7 User Stories
&lt;/h3&gt;

&lt;p&gt;Help understand a future feature to be implemented, its intent, and the purpose for the users. A user story (US) contains the requirements and specifies the acceptance criteria to clarify how to consider the feature ready. The US is a communication bridge between a product owner and a developer, as all content is recorded. A must-have to start coding! &lt;em&gt;Tools&lt;/em&gt;: Jira, Trello, Asana.&lt;/p&gt;

&lt;h3&gt;
  
  
  #8 Bug reports
&lt;/h3&gt;

&lt;p&gt;They have two main goals: 1) Get information about a newly notified bug, how it impacts the users, what its consequences are, what the error messages available are, and how to reproduce it 2) Find information on a previously fixed bug, as we currently investigate a similar one; you search how this previous bug was fixed, to help you in your work. They’re crucial to ensure the bug is fixed and to implement &lt;a href="https://www.packmind.com/dantotsu-best-practices/" rel="noopener noreferrer"&gt;countermeasures&lt;/a&gt;. &lt;em&gt;Tools&lt;/em&gt;: Linear, Jira.&lt;/p&gt;

&lt;h3&gt;
  
  
  #9 Executable specifications
&lt;/h3&gt;

&lt;p&gt;Behavior-Driven Development (BDD) helps generate scenarios that illustrate business domain use cases from which you can establish business rules. Business experts, developers, and stakeholders (such as QA engineers) have co-built the concrete behavior examples. You can formulate these examples with &lt;a href="https://cucumber.io/docs/guides/overview/" rel="noopener noreferrer"&gt;the Gherkin syntax&lt;/a&gt;. During your onboarding, these examples help you to get familiar with the business domain. It drives the coding process, especially when using TDD. &lt;em&gt;Tools&lt;/em&gt;: Cucumber, Cukedoctor.&lt;/p&gt;

&lt;h3&gt;
  
  
  #10 Architectural schemas
&lt;/h3&gt;

&lt;p&gt;This high-level material can sum up a software project's big picture, the main components, and how they interact together. It’s useful when onboarding a new project to understand better how things work. Diagram flows or UML schemas can also document the software at a high level of abstraction. It can be inappropriate for some software, as you can self-document an adequate code architecture. Retro-engineering and code analysis can also provide insights into the code's architecture. &lt;em&gt;Tools&lt;/em&gt;: Notion, CodeSee.&lt;/p&gt;

&lt;h3&gt;
  
  
  #11 The technical debt overview
&lt;/h3&gt;

&lt;p&gt;I take a shortcut with the term “&lt;a href="https://www.packmind.com/avoid-accidental-complexity-technical-debt/" rel="noopener noreferrer"&gt;technical debt&lt;/a&gt;” to consider the parts of the code that &lt;em&gt;require a rework&lt;/em&gt; — not only because the code is complex, but because the implementation, as it is, might raise issues in the short/middle term if nothing changes. The overview of the source code parts annotated as &lt;em&gt;tech debt&lt;/em&gt; can help prioritize remediation and estimate the effort to provide. &lt;em&gt;Tools&lt;/em&gt;: StepSize, CodeScene.&lt;/p&gt;

&lt;h3&gt;
  
  
  #12 Answers to a technical issue
&lt;/h3&gt;

&lt;p&gt;Not easy to categorize, but here I refer to every blocking issue we face when coding or building the application, such as a compilation issue. When you’re stuck and can’t find an answer in the documentation, you can use async channels to ask if someone has met a similar problem. The answer unblocks the workflow, and you can resume your job. You can find the answer inside the company or over the internet. &lt;em&gt;Tools:&lt;/em&gt; StackOverflow, Slack, CodeStream.&lt;/p&gt;

&lt;h3&gt;
  
  
  #13 Architectural Decision Records (ADR)
&lt;/h3&gt;

&lt;p&gt;An ADR is a document that captures essential decisions such as design choices, trade-offs, and rationales related to the architecture of the software. It serves as a historical record and provides transparency and accountability for architectural decisions. An ADR also gives information about its context and its consequences. Helpful when you join a project to get insights into the architecture evolution. &lt;em&gt;Tools&lt;/em&gt;: Markdown files embedded in the Git repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  #14 UI Prototypes
&lt;/h3&gt;

&lt;p&gt;Front-end developers are keen on consuming UI prototypes that reflect what’s expected regarding user interface and screens. It helps understand the user workflow and provides a clear overview of the user experience on the feature under development. They’re necessary to get started with the design implementation, accessing CSS elements, and producing a result that matches precisely the prototypes. &lt;em&gt;Tools&lt;/em&gt;: Figma, Adobe XD.&lt;/p&gt;

&lt;h3&gt;
  
  
  #15 Design System
&lt;/h3&gt;

&lt;p&gt;A system to centralize and reuse components related to the design of a product, a domain, or a company. Mainly helpful for front-end developers to ensure they ship source code with up-to-date design elements (logo, font, icons, …). Known as a central place where we can find information related to design decisions. &lt;em&gt;Tools&lt;/em&gt;: Storybook.&lt;/p&gt;

&lt;h3&gt;
  
  
  #16 Runtime logs
&lt;/h3&gt;

&lt;p&gt;They give valuable information on the runtime behaviors of your code. They help you investigate a bug report or analyze the performance of your software. Logs are essential for the observability of our software, and they provide precious insights into what happens in practice (how many times a service is called, how long last a service execution, …). All developers should have access to the logs in production. &lt;em&gt;Tools&lt;/em&gt;: Logtail, Logz.io, Loggly. &lt;/p&gt;

&lt;h3&gt;
  
  
  #17 Code history
&lt;/h3&gt;

&lt;p&gt;Helpful when you need to understand how a piece of code came up to its current state or if you realize the state has changed from the last time you saw this code and would like to know what happened. Versioning with Git provides excellent support and sometimes brings you to archeology work. You can identify the latest editor of a code and get in touch with him/her for further questions. The previous commits also give visibility to the current work. &lt;em&gt;Tools:&lt;/em&gt; Any Git client*,* GitHub, &lt;a href="https://www.gitkraken.com/" rel="noopener noreferrer"&gt;GitKraken&lt;/a&gt;, GitLab.&lt;/p&gt;

&lt;h3&gt;
  
  
  #18 Build statuses
&lt;/h3&gt;

&lt;p&gt;Hit by a developer to check if the branch merging doesn’t raise any issues or to get more information about a broken build (likely to be a failed test). This information is read on-demand and usually not on every push on the Git repository since alerting systems send notifications when there’s an issue (and not when all is fine). The build status indicates whether the code is ready for production. &lt;em&gt;Tools:&lt;/em&gt; Jenkins, GitLab CI, GitHub Actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  #19 Learning resources
&lt;/h3&gt;

&lt;p&gt;Developers can learn from their current projects and grow personal skills in specific concepts in parallel. E-learning resources allow async learning sessions to be completed when it suits your planning. Practice sessions are helpful in training on a new language you’d like to progress on. For instance, we also include blog posts shared in internal channels within a &lt;a href="https://www.packmind.com/community-of-practice-in-software-engineering-teams/" rel="noopener noreferrer"&gt;Community of Practice&lt;/a&gt;. It’s part of the continuous improvement process and the &lt;a href="https://www.packmind.com/learning-culture-software-developers/" rel="noopener noreferrer"&gt;learning culture&lt;/a&gt;. &lt;em&gt;Tools&lt;/em&gt;: Pluralsight, Udemy, Internal wikis, books. &lt;/p&gt;

&lt;h3&gt;
  
  
  #20 Product documentation
&lt;/h3&gt;

&lt;p&gt;Often forgotten, it still gives precious information on how the software behaves and helps to understand the application's different use cases and user workflows. It makes sense if the software is quite complex. Technical writers maintain this documentation; you might do it in some context. &lt;em&gt;Tools&lt;/em&gt;: GitBook, Intercom, Zendesk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;We’re done with this list! One last question for you now: how many sources do you have access to among this list? Do you have more suggestions? We’d be happy to add them, especially if you regularly hit some information or knowledge not mentioned in this post. Thanks!&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>gratitude</category>
    </item>
    <item>
      <title>What’s a best coding practice, and when to create it?</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Wed, 01 Feb 2023 08:36:47 +0000</pubDate>
      <link>https://dev.to/packmind/whats-a-best-coding-practice-and-when-to-create-it-fnn</link>
      <guid>https://dev.to/packmind/whats-a-best-coding-practice-and-when-to-create-it-fnn</guid>
      <description>&lt;p&gt;A best coding practice is a specific action in a particular context, it’s a way of doing things to achieve a specific result. These practices differ between companies and sometimes even between teams within the same company.&lt;/p&gt;

&lt;p&gt;Unfortunately, it’s rare that &lt;a href="https://www.packmind.com/open-source-linters-2021/"&gt;static analysis tools&lt;/a&gt; (linters) can automatically identify all these coding practices, which go beyond the syntax of the code. That's why it's crucial the whole team is aligned with them.&lt;/p&gt;

&lt;p&gt;With this in mind, we created &lt;a href="https://packmind.com/"&gt;Packmind&lt;/a&gt;, a solution that centralizes your team’s best coding practices.&lt;/p&gt;

&lt;p&gt;A coding practice in Packmind is made of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a name&lt;/li&gt;
&lt;li&gt;a description&lt;/li&gt;
&lt;li&gt;categories&lt;/li&gt;
&lt;li&gt;code examples (positive, negative, and refactoring)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fPFChfAq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AwMLk8KG17S1BAlKO.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fPFChfAq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AwMLk8KG17S1BAlKO.webp" alt="An example of best practice" width="720" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why define and share best coding practices?
&lt;/h2&gt;

&lt;p&gt;As companies aim to deliver value as quickly as possible and avoid bugs that are harmful to their business, they must capitalize on the collective intelligence of all their teams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/blog/products/devops-sre/dora-2022-accelerate-state-of-devops-report-now-out?hl=en"&gt;Accelerate&lt;/a&gt; has highlighted in its study that the most successful companies from an IT point of view have implemented a "&lt;a href="https://www.packmind.com/learning-culture-software-developers/"&gt;Learning Culture&lt;/a&gt;," which promotes continuous learning and knowledge sharing. This helps to cope mainly with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Heterogeneity of skills in teams&lt;/strong&gt; — everyone can learn from the skills of their colleagues and thus strengthen the team's skills as a whole.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turnover&lt;/strong&gt; — newcomers can quickly become familiar with the company's practices, which reduces adaptation time and the risk of losing skills when they leave.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rapidly evolving technologies&lt;/strong&gt; — best practices are constantly being renewed, new languages and frameworks appear regularly, so it is important to stay up to date with this. Moreover, on a personal level, this allows developers to remain competitive in a constantly evolving market.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to create a best coding practice?
&lt;/h2&gt;

&lt;p&gt;For the whole team to contribute to this knowledge sharing, everyone must have in mind "when" he can create a practice.&lt;/p&gt;

&lt;p&gt;In order not to leave the working environment, it must happen when you’re writing code (from your IDE) or when you’re reviewing code (on a &lt;a href="https://docs.gitlab.com/ee/user/project/merge_requests/"&gt;merge request in GitLab&lt;/a&gt;, for example).&lt;/p&gt;

&lt;p&gt;Packmind plugins make this creation easier by allowing the team to &lt;a href="https://www.packmind.com/create-best-coding-practices/"&gt;create these practices&lt;/a&gt; in seconds.&lt;/p&gt;

&lt;p&gt;2 main scenarios should lead to best practice creation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A bug has been identified that stems from a poor design or code error;&lt;/li&gt;
&lt;li&gt;An improvement has been made to the source code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A bug has been identified that stems from a poor design or code error;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“One should always learn from your mistakes.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Strongly linked to the "&lt;a href="https://www.packmind.com/dantotsu-best-practices/"&gt;Dantotsu&lt;/a&gt;" approach, the idea is to use each bug as a learning source. Each problem is then presented to the team, and one or several practices can emerge from these discussions.&lt;/p&gt;

&lt;p&gt;This is obviously also true for potential bugs that could be avoided, for example, if they’re identified during a code review; in this case, the Packmind plugins allow you to create this practice directly when you add a comment during the code review.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For example: A bug is identified in an AngularJS component, a disconnection should have occurred when the component is destroyed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xA5Eokes--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AgdZZo6GTbj_8ztRT" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xA5Eokes--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AgdZZo6GTbj_8ztRT" alt="Bug in AngularJS" width="720" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And here is the associated fix to follow the best practice.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l_taaRH---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AO-tQ_fFwCRVMn3p_" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l_taaRH---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AO-tQ_fFwCRVMn3p_" alt="Fixed Bug in AngularJS" width="720" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  An improvement has been made to the source code
&lt;/h3&gt;

&lt;p&gt;Because the source code is constantly evolving, our practices are constantly being challenged. When a practice evolves, it’s rare to modify the entire source code of the product to follow it. It’s, therefore, common to find many different ways of doing things in the same source code.&lt;/p&gt;

&lt;p&gt;When a practice evolves, it must be presented to the whole team, and this change must be recorded somewhere. Otherwise, it’s only local and doesn’t last over time.&lt;/p&gt;

&lt;p&gt;These practice changes can be of multiple natures, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A new concept is introduced in the codebase&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adding a new system in the app, to call when adding a new object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ysMKKqzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AleSqH_OTtwdympfF" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ysMKKqzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AleSqH_OTtwdympfF" alt="Trigger event" width="720" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improvements in the code architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Setting up a new pattern to highlight the &lt;em&gt;infrastructure layer&lt;/em&gt; level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eke_83Ev--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AXUKvPEC7h5jNGvj0" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eke_83Ev--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2AXUKvPEC7h5jNGvj0" alt="Infra layer" width="720" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An example that features the outdated convention.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JYDAgwkl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2ACGPmhW_8htJHKSXx" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JYDAgwkl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/max/720/0%2ACGPmhW_8htJHKSXx" alt="Infra correction" width="720" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance, security, and accessibility improvements&lt;/li&gt;
&lt;li&gt;Maintainability improvements (such as better readability of the source code).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sure, we could list a few more, but these four examples are the main ones that would make your team want to start sharing best coding practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;In conclusion, it’s key to share practices within the team to &lt;a href="https://www.packmind.com/set-learning-culture/"&gt;improve the &lt;strong&gt;&lt;em&gt;lead time&lt;/em&gt;&lt;/strong&gt; and reduce the &lt;strong&gt;&lt;em&gt;change failure rate&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;. Tech leads must be the drivers and ambassadors of this approach to boost the involvement of the rest of the team.&lt;/p&gt;

&lt;p&gt;It’s important not to overestimate the knowledge of other team members. Known as the &lt;em&gt;Curse of knowledge&lt;/em&gt;, this phenomenon translates into the tendency to think that other people know the same things as we do, so we limit the practices to be presented, even though some of them are probably unknown to our colleagues.&lt;/p&gt;

&lt;p&gt;These practices should be shared with all the teams in the company and not only with your team. They’re also valuable for the next team members, so we must think beyond our team when we identify a coding practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want to discover a new way to share your best coding practices as a team? Start now for free with &lt;a href="https://packmind.com/"&gt;Packmind&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Dantotsu method: from bug to best practice</title>
      <dc:creator>Cédric Teyton</dc:creator>
      <pubDate>Thu, 26 Jan 2023 09:42:23 +0000</pubDate>
      <link>https://dev.to/packmind/dantotsu-method-from-bug-to-best-practice-2mkn</link>
      <guid>https://dev.to/packmind/dantotsu-method-from-bug-to-best-practice-2mkn</guid>
      <description>&lt;p&gt;During autumn 2022, I had the chance to attend the great &lt;a href="https://flowcon.fr/"&gt;FlowCon&lt;/a&gt; conference hosted in Paris, France, whose core topic targets stream delivery in software engineering. Lean, Agility and Continuous delivery are thus highly represented in the conference. One of the talks caught my attention, and I was far from disappointed when I saw it; The talk was realized by Woody Rousseau and Flavian Hautbois (The &lt;a href="https://www.youtube.com/watch?v=X6r6WtKuF2k"&gt;replay&lt;/a&gt; is in French here, but there’s a &lt;a href="https://www.youtube.com/watch?v=P_eGpP5y-vY"&gt;talk in English&lt;/a&gt; on the same topic made at the Craft Conference 2022). I can translate its title to “Radical Quality - from Toyota to IT.” In this post, I share some insights from this talk, especially the &lt;strong&gt;Dantotsu&lt;/strong&gt; method, which was new to me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Dantotsu and Radical Quality at Toyota
&lt;/h2&gt;

&lt;p&gt;The talk relates the story of Sadao Nomura, who worked at Toyota between 2006 and 2015 to solve a pain point on quality issues. Before he joined Toyota, the company had a non-satisfying number of internal defects in its factory chains. Because of these &lt;em&gt;bugs&lt;/em&gt;, it was common that the requirements to ship cars outside the factory weren’t met. Toyota really wanted to work on that to make sure the expected levels of quality were satisfied more frequently. And so Sadao Nomura came in. &lt;/p&gt;

&lt;p&gt;Sadao Nomura aimed to generate a 50% reduction in the number of defects on the factory chains for three years (meaning an overall ~88% of the global reduction for the full period). He told the full story in his book &lt;em&gt;The Toyota Way of Dantotsu Radical Quality Improvement&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_-xCAWun--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://promyze.com/wp-content/uploads/image-370x370.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_-xCAWun--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://promyze.com/wp-content/uploads/image-370x370.png" alt="Dantotsu Radical Quality Improvment" width="370" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dantotsu means “&lt;em&gt;Better than the best.”&lt;/em&gt; This radical approach challenges what companies usually settle to tackle quality issues. What are these ideas?  &lt;/p&gt;

&lt;h2&gt;
  
  
  Eradicate defects and ensure they won't happen again
&lt;/h2&gt;

&lt;p&gt;Why use the &lt;strong&gt;&lt;em&gt;radical&lt;/em&gt;&lt;/strong&gt; term when referring to Dantotsu? Because the philosophy isn’t about quickly fixing a defect, it's also about deeply understanding &lt;strong&gt;why&lt;/strong&gt; this defect happened, what's been done to resolve it, and how to avoid this occurring again in the future. These are the core principles of Dantotsu. &lt;/p&gt;

&lt;p&gt;In the book, Nomura explains different aspects of the approach, particularly the importance of visual management and the training programs (Dojos), where workers can practice the right gestures to avoid defects. He also provides an interesting classification of the defects. In Tech, we often use the priority (Low/Medium/High…). He suggests using the four following types of bugs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type &lt;strong&gt;A&lt;/strong&gt;: The defect is caught within the team and has no impact outside ;&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;B&lt;/strong&gt;: The defect goes to another team within the company ;&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;C&lt;/strong&gt;: The defect is undergone by a third party or subcontractor ;&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;D&lt;/strong&gt;: The defect is undergone by the customer/final user (the worst situation, of course).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, what happens when a defect is identified? In the context of Toyota, when a single unit has an issue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the team leader in charge of the area first makes sure that no other pieces have the same issue;&lt;/li&gt;
&lt;li&gt;the root cause of the &lt;strong&gt;issue is identified and fixed;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;counter-measures&lt;/strong&gt; are taken to avoid the defect from happening again;&lt;/li&gt;
&lt;li&gt;a report is shared with the whole team to explain the 3 previous points;&lt;/li&gt;
&lt;li&gt;It doesn’t stop here. The team leader also reports to &lt;strong&gt;other team leaders&lt;/strong&gt; of areas where a similar defect can occur, and they’re &lt;strong&gt;trained&lt;/strong&gt; to fix the issue as well. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(The process has 8 steps for the record, which I’ve summarized for simplicity).&lt;/p&gt;

&lt;p&gt;And all this process happens in 24 hours. Radical right? Speed is key. When we see a defect, don't just fix it. We don't want to see him again. This approach turned out to be successful in practice at Toyota. &lt;/p&gt;

&lt;h2&gt;
  
  
  Dantotsu in Software Engineering?
&lt;/h2&gt;

&lt;p&gt;The second part of the talk was about how the Dantotsu method &lt;strong&gt;was implemented in two tech companies&lt;/strong&gt;. They recall that, in software engineering, there’s still work to do to convince people that &lt;a href="https://www.packmind.com/do-clean-code/"&gt;doing things&lt;/a&gt; right costs less than non-quality (surprising, right?). If you’re skeptical about this statement, we recommend you to read &lt;a href="https://www.amazon.com/Economics-Software-Quality-Capers-Jones/dp/0132582201"&gt;The Economics of Software Quality&lt;/a&gt; which precisely demonstrates the cost of bad software quality. The &lt;a href="https://www.amazon.com/Accelerate-Software-Performing-Technology-Organizations/dp/1942788339"&gt;Accelerate&lt;/a&gt; book closes the discussion on that question if it's still needed. &lt;/p&gt;

&lt;p&gt;The two speakers in the talk explain that to reach the zero-defect (utopian) ambition, the key part is to &lt;strong&gt;train developers&lt;/strong&gt; to produce source code with no defects. They also transpose the bug categorization into the software engineering world, so, for instance, Type A is a defect caught by developers locally or during the &lt;strong&gt;continuous integration step&lt;/strong&gt;. In their respective company, they've both implemented a new process where defects are documented, especially the investigation and the countermeasure. Here's a capture of one slide that encompasses all the information: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nrYm4F1w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Slide-extracted-from-the-conference-1536x809.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nrYm4F1w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Slide-extracted-from-the-conference-1536x809.png" alt="Slide extracted from the conference. " width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we can see the deep level of details where they go to document what's been wrong, and indicate that the countermeasure was to consolidate the tests. (Disclaimer: not surprisingly, consolidating the tests is a common countermeasure). NB: the two quoted companies in the conference used wiki-like systems to document these defects.&lt;/p&gt;

&lt;p&gt;Also, in their companies, they've set regular meetings dedicated to &lt;strong&gt;bugs&lt;/strong&gt;. In these sessions, someone can present to the other participants a bug report and goes deep into the root cause and how to prevent it again. Similar to what happened in the Toyota factories, someone is showing the right gestures to avoid a problem happening again. If the sessions can be opened to anyone, it can also gather the Tech leaders, who will ensure the message is broadcasted to their respective teams.  &lt;/p&gt;

&lt;p&gt;What were their conclusions after the implementation of this methodology? I won’t mention all the details, but here are some interesting insights:&lt;br&gt;
&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A strengthened culture of software quality and more open discussions around bugs;&lt;/li&gt;
&lt;li&gt;One of the speaker’s team achieved an &lt;strong&gt;81%&lt;/strong&gt; decrease in defects in production in 3 quarters. The trend is less visible at the company level, even though it is positive, but it’s a longer-term goal to show results at this level;&lt;/li&gt;
&lt;li&gt;For the other speaker, they had a &lt;strong&gt;50%&lt;/strong&gt; reduction of new bugs in production in 3 quarters, and also, they got twice more bugs resolved in less than &lt;strong&gt;24 hours&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenges:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hard to address the stock of bugs, especially if they were introduced several months ago. Speakers talk about doing Archaeology sometimes;&lt;/li&gt;
&lt;li&gt;A deep analysis of a bug requires time (~2 hours) for someone trained, but Tech Lead has others duties in their work. So there’s a balance to find;&lt;/li&gt;
&lt;li&gt;Sometimes discussions go beyond technical aspects, to address collaboration issues related to communication or pressures on delivery (that still need to be solved as well).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So yes, the Dantotsu philosophy can be transferred to the Software industry. It’s easier to fix a defect in our code when others developers have met it before. The overall method won’t be smooth and easy initially, but it’s worth a shot!&lt;/p&gt;

&lt;h2&gt;
  
  
  From Defect to Coding Best Practice
&lt;/h2&gt;

&lt;p&gt;We saw that when a bug is found in the &lt;strong&gt;source code&lt;/strong&gt; and fixed, this should be turned into shared knowledge for the team (so that it won't happen again, remember?). That's what's shown in the screenshot above. An easy way to perform this operation is to use the &lt;a href="https://packmind.com"&gt;Packmind&lt;/a&gt; platform, which aims to ease best practices sharing in engineering teams with deep integration in developers’ tools (IDE &amp;amp; Code Reviews). Developers are keen on sharing best practices in many situations, such as performance improvement, security fixes, better readability, or &lt;strong&gt;bug fix&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Let's see an example of how to proceed with a concrete example of a defect fixed in late 2022 internally. In our staging environment, before a final release, we spotted an error when our application started and performed patches on the &lt;a href="https://www.packmind.com/simple-api-healthcheck-with-node-express-and-mongodb/"&gt;MongoDB&lt;/a&gt; database. In our code, a method from the &lt;strong&gt;Mongoose&lt;/strong&gt; framework was called to regenerate the indexes of a collection. We observed runtime issues and found this method should rather not be called in our context (this last point is an important precision; I'm not saying you should never call this method, but in short, it wasn’t compatible with our system).&lt;/p&gt;

&lt;p&gt;Let’s see how we propose to adapt the Dantotsu process to Packmind. &lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Identify the defect &amp;amp; fix it&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The defect has been spotted in the code, and we removed the call to &lt;em&gt;reIndex&lt;/em&gt;(). Before that, we created a best practice from VSCode using the Packmind extension: &lt;em&gt;Selection of code → Right Click → Packmind → Identify a new best practice&lt;/em&gt;. Just put a name, and this is sent to the Packmind application. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xWkAx9G---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AthDEkLSgnAqWwCIqV6NVpg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xWkAx9G---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AthDEkLSgnAqWwCIqV6NVpg.gif" alt="Defect identification in Packmind" width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Report with the team &lt;strong&gt;&amp;amp; beyond&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Then, with Packmind, our team (a project team, feature team, or even a &lt;a href="https://www.packmind.com/community-of-practice-in-software-engineering-teams/"&gt;community of practice&lt;/a&gt;) runs regular workshops to review best practices proposals. Each contributor explains the intent behind the suggested practice. In our case, Arthur explained to the whole team the issue met with the &lt;em&gt;reIndex&lt;/em&gt; function call, and everyone could indicate if this was clear to them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k-BZPodZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://promyze.com/wp-content/uploads/Untitled-7-1536x847.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k-BZPodZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://promyze.com/wp-content/uploads/Untitled-7-1536x847.png" alt="Practices review during workshop" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the best practice has been validated, it can be shared with others teams in the organization, or within a community of practice. The knowledge is spread beyond teams. &lt;/p&gt;

&lt;h3&gt;
  
  
  3. Implement countermeasures
&lt;/h3&gt;

&lt;p&gt;Once a best practice has been validated, you can set regular expressions that match the pattern you want to avoid to push &lt;a href="https://www.packmind.com/automatic-suggestions/"&gt;notifications&lt;/a&gt; in developers’ IDE and Code reviews (a &lt;em&gt;linter-like&lt;/em&gt; behavior). This will be possible if your pattern can be matched by the syntax of the code. It will reduce the risk that this method will be used in the future. &lt;/p&gt;

&lt;p&gt;This is what it looks like when configuring a regex in Packmind, and then getting suggestions in VSCode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N9-4pmOd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AGjMYu1iH8GASfB6ZJ3JOcw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N9-4pmOd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2AGjMYu1iH8GASfB6ZJ3JOcw.gif" alt="Automatic suggestions in Packmind" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Train people
&lt;/h3&gt;

&lt;p&gt;When new developers join your organization, they need to get familiar with your best coding practices, and also the patterns to avoid defects. In Packmind, there is a feature called &lt;a href="https://www.packmind.com/onboarding-developers-best-coding-practices/"&gt;onboarding workshop&lt;/a&gt; for new hires, where they can train on your knowledge base. As each best practice has associated code files, each recruit will be invited to locate the area where the best practice has been followed (or, inversely, not applied). In the example below, they’ll need to highlight line number 6:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HeSKtz0g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Untitled1-1536x717.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HeSKtz0g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.promyze.com/wp-content/uploads/Untitled1-1536x717.png" alt="Onboarding workshop with Packmind" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;What happened here is that we caught a bug and fixed it, and in addition, we capitalized on our work and generated a new best coding practice from it. We tried to follow the Dantotsu philosophy!&lt;/p&gt;

&lt;p&gt;If you have never heard about it before, I hope this short introduction helped you to get a better overview of &lt;strong&gt;Dantotsu&lt;/strong&gt;. I'd be happy to have your feedback. Have you implemented the Dantotsu in your context? Please share!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
