人類にコードレビューは早すぎた〜わんにゃん大集合〜

[クソアプリアドベントカレンダー2019](https://qiita.com/advent-calendar/2019/kuso-app)の14日目です。

# コードレビューって難しい☠️

みなさん
コードレビューちゃんとできてますか？
人格攻撃しないっていうけど本当にできてますか？
貴方のレビューで悲しんだレビュイーは本当にいませんか？
レビュイーによって指摘内容が変わりませんか？
レビューを素直に受け止められてますか？
その日の気分やレビュワーによって受け取り方変わりませんか？

## 人格攻撃じゃない真っ当なレビューでも辛いときもある📛

僕は豆腐メンタルなので人格攻撃じゃない真っ当なレビューでも
「あ、オレ全然ダメじゃん…つら…」
ってなることが時々あります📛

## レビュイーによって指摘内容が変わる

強い人のプルリクを見るときは
「あ、この人がこう作ってるのは別パターンより良いってことなんだな」
みたいな忖度、ちょっとしちゃいます。
なぜそうしてるのかは聞くくらいで終わったり。
にんげんだもの。

# コードレビューは人類には早すぎた

ここまで話せばみなさんも気づいたかもしれない。
そう。
人類にコードレビューは早すぎたのだ。

# 動物さんたちにやってもらおう

自分以外のレビュワー、レビュイーが動物になるChrome拡張機能『**プルリクエスト忍者**』を作りました。

[Pull Request Njinja](https://chrome.google.com/webstore/detail/pull-request-ninja/ipfacjdddjcncdkkklpldngpjipiapjb?hl=ja)
![screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218/94f6a0b6-7582-a78f-10dd-c2de27d1df3a.png)

## やったね！動物さんたちなら安心だね！

動物になら優しくなれますよね？
やりましたね。これで全て解決です。
もう人間はいりません。

# 実装

Chrome拡張はブラウザ上で実行したいJsさえ書ければ簡単に実装、公開できます。
今回書いたのはこれくらい

```js:content.js
// アドレスバー横の拡張機能ボタンを押された時のリスナー用意
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
  if (request == 'toggle') {
    toggleNinja();
  }
});

('use strict');

let isHide = false;
// 登場する動物さんたち
const dummyNames = [
  '🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐨', '🐯', '🦁', '🐮', '🐷'
];
const currentUserIconUrl = $('.Header-link .avatar')[0].src;
const currentUserName = $('.header-nav-current-user strong')[0].textContent;
let iconUrls = [];
let userNames = [];

// ページ上にあるユーザー名とアイコンのURLを取得
$('img.avatar[alt^="@"]').each((_, element) => {
  // @削除
  const userName = element.alt.slice(1);
  if (
    !userName ||
    currentUserName == userName ||
    userNames.indexOf(userName) >= 0
  ) {
    return;
  }
  iconUrls.push(element.src);
  userNames.push(userName);
});
toggleNinja();

// ユーザー名とアイコンを動物さんにチェンジ！さよなら人類！
function toggleNinja() {
  isHide = !isHide;

  if (isHide) {
    userNames.forEach((userName, index) => {
      $(`[href$='/${userName}']`).each((_, element) => {
        if (
          element.childElementCount > 0 &&
          element.firstElementChild.tagName == 'IMG'
        ) {
          const lastChild = element.lastElementChild;
          if (lastChild.className == 'dummnyName') {
            lastChild.style.display = 'inline';
          } else {
            const nameDom = document.createElement('span');
            nameDom.textContent = dummyNames[index];
            nameDom.className = 'dummnyName';
            element.appendChild(nameDom);
          }
          element.firstElementChild.style.display = 'none';
        } else {
          element.dataset.originalText = element.text;
          element.text = dummyNames[index];
        }
      });
    });
  } else {
    userNames.forEach((userName, _) => {
      $(`[href$='/${userName}']`).each((_, element) => {
        if (
          element.childElementCount > 0 &&
          element.firstElementChild.tagName == 'IMG'
        ) {
          element.firstElementChild.style.display = '';
          element.lastElementChild.style.display = 'none';
        } else {
          element.text = element.dataset.originalText;
        }
      });
    });
  }
}
```

その他設定などはリポジトリを参照してください
[akinov/pull-request-ninja: Hide Assignees &amp; Reviewers for GitHub](https://github.com/akinov/pull-request-ninja)

# 反省

これで全て解決はしたのですが少しだけ反省点があります。

## 機能的にクソアプリ

読み込み時に一瞬元アイコンと真名が見えてしまいます。
英霊としてはこれは致命傷。
宝具がバレてしまいます。

## アプリ名がイケてない

以前、Facebookメッセンジャーのメッセ相手の名前とアイコンを隠すChrome拡張機能『[Messenger Ninja](https://chrome.google.com/webstore/detail/messenger-ninja/amnelmmcdcdcigkoakjnnlpicemkkjfm?hl=ja)』を作っていたので
「何かを隠す、隠れるなら忍者だろ！」
とプルリク忍者という拡張名にしたけど
『**プルリクエスト動物園**』とかのほうが絶対可愛かった…
反省…🐒