仮想DOMとは

Vue.jsを触ると仮想DOMという概念が出てくるので簡単に整理してみる。

概要

  • 効率良くDOMを操作するにはどうすれば良いか?

例えば、以下のようなコードがありage+10するボタンを3回押してみるとageは50になる
この場合のDOMの変化は<p>age: {{ age }}</p>のみである、他は変化していない
ということは変化した部分のみを差し替えればいいのではないか!!!

そこで登場するにが仮想DOMである。

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>

<div id="example-1">
  <button v-on:click="counter += 1">Add 1(num)</button>
  <p>The button above has been clicked {{ counter }} times.</p>
    
  <p>name:{{ name }}</p>
    
  <p>age: {{ age }}</p>
  <button @click="age += 10">Add 10(age)</button>
</div>
new Vue({
  el: '#example-1',
  data: {
    counter: 0,
        name: "太郎",
    age: 20
  }
})

  • 初期画面

f:id:gallard316:20210112143841p:plain


  • Add 10(age)ボタンを3回押したので50になった

f:id:gallard316:20210112143941p:plain


WikipediaのReactより

もう1つの注目すべき機能は、仮想DOMの使用である。Reactでは仮想DOMとしてメモリ上にDOMの状態をキャッシュしておき、仮想DOMに差分が発生した場合にのみ差分を計算し、実際のDOMに差分のみを反映させることにより効率的な描画を実現している

  • 実際の動き
  • 仮想DOMを二つ用意

  • 一方の仮想DOMをJavascriptで操作(一般的にリアルDOMを操作するより速い)
  • 変更前後の仮想DOMの差分を比較
  • 差分だけをリアルDOMに反映
  • 反映されたリアルDOMをブラウザがレンダリング

ということで最終的にリアルDOMを操作するのですが、通常、リアルDOMを操作する場合はリアルDOMが変更されるたびにブラウザがHTMLを解析してレンダリングするのでコストが高いです。

結局、結論としては「設計と速度が両立させるため」。

Vueを触る際の注意点

一点だけパフォーマンス上の理由で知らないといけないものがあります。

key 特別属性は、主に古いリストの代わりにノードの新しいリストを差分算出する VNode を識別するために Vue の仮想 DOM アルゴリズムに対するヒントとして使用されます。キーがない場合、Vue は要素の移動を最小限に抑えるアルゴリズムを使用し、可能な限りその場で同じタイプの要素にパッチ適用/再利用しようとします。
キーがある場合は、キーの順序の変化に基づいて要素を並べ替え、そして、もはや存在しないキーを持つ要素は常に削除/破棄されます。
同じ共通の親を持つ子は、一意なキーを持っていなければなりません。重複するキーはエラーを描画する原因になります。


  • 例を使って実際の動きを見てみる
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>

<div id="example-2">
<ul>
  <div v-for="fruit in fruits">
      <p>{{ fruit }}</p>
          <input type="text">
  </div>
</ul>
<button @click="remove">先頭を削除</button>
</div>
new Vue({
  el: '#example-2',
  data: {
    fruits: ["apple", "orange", "grape"]
  },
  methods: {
      remove: function() {
          this.fruits.shift()
      }
  }
})

  • それぞれに文字を打ってみる

f:id:gallard316:20210112153035p:plain


  • 削除ボタンを押すとズレる

f:id:gallard316:20210112153125p:plain


なぜこうなるのかというと先ほどの引用にあるこれが原因

「キーがない場合、Vue は要素の移動を最小限に抑えるアルゴリズムを使用し、可能な限りその場で同じタイプの要素にパッチ適用/再利用しようとします」

この予期せぬバグに対処するためにkey属性を指定します

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>

<div id="example-2">
<ul>
  <div v-for="fruit in fruits" :key="fruit">
      <p>{{ fruit }}</p>
        <input type="text">
    </div>
</ul>
<button @click="remove">先頭を削除</button>
</div>

key属性をつけることにより意図したように先頭が削除されました。

f:id:gallard316:20210112153919p:plain

key属性については

  • v-forでは必須
  • 一意になるようにする
    • 要素をkey属性にする場合、重複していると一意にならないのでオブジェクトでidを指定するなど
  • indexをkey属性にしない

ja.wikipedia.org

qiita.com

qiita.com

saneyukis.hatenablog.com

eh-career.com

jp.vuejs.org

アジャイル開発について

アジャイル開発について調べたので書いて整理します。


 アジャイル(agile)の意味を調べてみると「機敏な」、「素早い」という意味になる。 そして、アジャイル開発を日本語にすると機敏な開発、素早い開発となり、そのまま解釈すると、開発期間が短縮される開発手法になる。 実際、アジャイル開発は納期が短縮されることが期待される開発手法であり、またリスクを最小化できるというメリットがある。
では、具体的にアジャイルソフトウェア開発宣言が示している4つの価値をなぞりながらアジャイル開発を整理していく。

  • プロセスやツールよりも個人と対話を、
  • 包括的なドキュメントよりも動くソフトウェアを、
  • 契約交渉よりも顧客との協調を、
  • 計画に従うことよりも変化への対応を、

価値とする。すなわち、左記のことがらに価値があることを
認めながらも、私たちは右記のことがらにより価値をおく。


 動くソフトウェアとは、価値のあるソフトウェアを早く継続的に提供するということである。 価値のあるソフトウェアとは分析、設計、開発、テストされた(この一連の工程を短期間で繰り返す開発サイクルのことをイテレーションという)リリース可能なソフトウェアのことである。そして、動くソフトウェアこそが進捗の最も重要な尺度になる。
定期的に素早く成果を届けることで、顧客からフィードバックをもらうことができる。 フィードバックは顧客の意思を確認することにつながり、開発の方向性を調整するきっかけにもなる。

 これらの顧客との協調においては、当初の計画の変化が起きうることもある。 アジャイル開発では変化を恐れず、よりよい成果を生み出す機会と捉える。 機敏に、そして柔軟に計画を変更することが顧客のニーズに答えることにつながる。

 また、開発する上でチームが円滑に成長し続けていることも重要である。 例えば、イテレーションごとにミーティングを開催してもっとチーム内の状況を確認したり、チームの効率をもっと上げるためにはどうすれば良いかを検討することでベロシティ(一回のイテレーションの量)を高めることにつながる。

イテレーションとは?スプリントとの違いや開発プロセスを解説!|ITトレンド

アジャイル開発 ~顧客を巻き込みチーム一丸となってプロジェクトを推進する~ (前編): コラム | NECソリューションイノベータ

アジャイル開発とは?主流の開発手法「スクラム」も…|Udemy メディア

www.amazon.co.jp

DOMとは

javascriptに触れて数ヶ月、DOMについて何となく知っていたがまだフワッとしているので調べました。



DOMとは「Document Object Model」の略であり、日本語にすると「文書オブジェクトモデル」である。

文章をオブジェクトの木構造で表現する。そして操作するための仕組み、方法である。

文章とはWebページのこと。マークアップがなされた文章もdocumentである。
マークアップとはタイトルや見出しなどの各構成要素に「タグ」と呼ばれる識別のための目印を使い、意味付けを行っていくこと(htmlがまさにそうである)

そして、

Document内にはマークアップによって区切られるまとまりがあり、各まとまりを特定種のオブジェクトで表現する(例: <主語>これは</主語> = 主語オブジェクト)。
DOMにおいてオブジェクトは総称してNodeと呼ばれる。

Node(ノード)とは直訳で節であり、点と線で構成図を書いたときの点の部分のこと。

f:id:gallard316:20201231004003p:plain

さらに、

Nodeは入れ子構造をとるため、これを木構造(親Nodeと子Nodeの入れ子構造)でモデル化できる。

具体的にHTMLでNodeを見て見る。

f:id:gallard316:20201231004951p:plain

bodyタグ、sectionタグ、pタグで囲まれたものがオブジェクトであり、Nodeである。
そしてsectionタグを基準に見るとbodyタグは親ノード、pタグが子ノード、親を通して対にあるsectionノードが兄弟姉妹ノードである。

f:id:gallard316:20201231005046p:plain

このように親ノードを根として枝分かれしていく様子が木構造である。


DOMとは - Qiita

Document Object Model - Wikipedia

DOM の紹介 - Web API | MDN

Vue 描画について

”Mustache” 構文(二重中括弧)を利用したテキスト展開

”Mustache”とは口ひげの意味

プロパティ名を書くことで表示できる

<div id="app">
    <p>{{ message }}</p>
  </div>
new Vue({
  el: '#app',
  data: {
    message: "hello world"
  }
})




templateプロパティを使って表示

HTMLの方に書いていたものをそのまま書ける

<div id="app2"></div>
new Vue({
  el: '#app2',
  data: {
    name: "John"
  },
  template: "<h1>hello {{ name }}</h1>"
})




render関数を使って描画する

 <div id="app3"></div>
new Vue({
  el: '#app3',
  data: {
    name: "山田"
  },
  render: function(h) {
    return h("p", "こんにちは" + this.name + "さん" )
  }
})


VueCLIを使うとmain.jsに最初からある

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')


どんなものがあるか簡単に書いてみました。

プロセスとスレッド

気になってい他ことなので、メモがてら書きます。間違っているところもあるかもしれません。

意味

プロセス

プロセスとは、処理のことである。
コンピュータプログラムは命令の受動的集合体である。プロセスはそれら命令の実際の実行である。

例えでいうと、
chromeやターミナルを開くことや lsコマンドやwcコマンドを叩くこと。
それぞれが一つのプロセス (プログラム)

スレッド

スレッドとは、CPU利用の単位。
CPUは基本的に1つのコアで1つの処理しか実行することはできません。

例えでいうと、

ターミナルでlsコマンドを叩くと 「ファイルが読み込まれる」、「ターミナルの幅を計測する」、「最大文字数のファイル名を見つける」、「何列で表示するか決める」などなど
たくさんの処理が内側で行われている。それらひとつひとつがスレッド


つまり 1つのプロセスは、1つ以上のスレッドから構成される。

  • マルチプロセスとマルチスレッド

    マルチプロセス

    chrome・ターミナルなどそれぞれのプログラム(プロセス)を同時に開き、使うことができる。また、ターミナルのvimで複数のファイルにプログラムを書くことができ、それぞれのファイルは影響はしない。
    このようにプロセスを同時に実行(並列処理)することをマルチプロセスといいます。

  • マルチスレッド

    シングルスレッドのプロセス:1つしかスレッドを持たないプロセス
    マルチスレッドのプロセス:複数スレッドを持つプロセス

マルチスレッドの利点は、例えば、シングルスレッドの場合だと重い処理を待つ必要があり利便性にかけイライラする。しかしマルチスレッドの場合、重い処理と他の処理を分けることで並列処理できる。

メモリ領域

プロセスはシステム全体の動作の安定性および安全性の観点から、プロセスごとにメモリは独立して割り当てられる。
しかし。独立したメモリ空間が不必要な場合では、メモリの利用効率が悪くなってしまう。プログラムによっては、処理ごとに別々の空間にあるメモリを利用するのではなく、単一の空間内のメモリを共有しながら複数の処理を行なう「共有メモリ方式」のほうが、ロジックの実装のしやすさやメモリ効率の面で優れている場合がある。
これを可能にするのがスレッドである。
スレッドを使うことで、同一プロセス内の複数スレッドを同一メモリ空間上で実行でき、メモリ消費量などが軽減できるようになっている。
しかし、注意点もあり、同じデータを複数のスレッドが同時に書き換えることによる不整合が生じるので、排他制御(あるスレッドがリソースにアクセスしているときは、ほかのスレッドがアクセスできないようにロックをかけること)を行う必要がある。
また、複数のスレッドが協調動作する際、お互いの処理完了を待ち合わせてデッドロック (2つ以上のスレッドあるいはプロセスなどの処理単位が互いの処理終了を待ち、結果としてどの処理も先に進めなくなってしまうこと) 状態に陥ることのないよう配慮する必要もある。

ビンゴカードプログラム作成してみた(Ruby)

class Number
  def dimentional_number_array
    array_of_each_numbers = []
    array_of_each_numbers.push(select_five_numbers_in_B, select_five_numbers_in_I, select_five_numbers_in_N, select_five_numbers_in_G, select_five_numbers_in_O)
    array_of_each_numbers.transpose
  end

  private
  def select_five_numbers_in_B
    (1..15).to_a.sample(5)
  end

  def select_five_numbers_in_I
    (16..30).to_a.sample(5)
  end

  def select_five_numbers_in_N
    (31..45).to_a.sample(4).insert(2, ' ')
  end

  def select_five_numbers_in_G
    (46..60).to_a.sample(5)
  end

  def select_five_numbers_in_O
    (61..75).to_a.sample(5)
  end
end

class Bingo
  def initialize
    @dimentional_number_array = Number.new.dimentional_number_array
  end

  def create_card
    enumerate_in_a_low(bingo_words)
    @dimentional_number_array.each do |number_array|
      enumerate_in_a_low(number_array)
    end
  end

  private
  def bingo_words
    'BINGO'.split(//)
  end

  def enumerate_in_a_low(array)
    print ' '
    array.each do |e|
      print e.to_s.rjust(2)
      if e == array[4]
        puts
      else
        print ' | '
      end
    end
  end
end

Bingo.new.create_card
  • コンソール表示
~ % ruby bingo.rb
  B |  I |  N |  G |  O
 13 | 16 | 45 | 46 | 71
  8 | 19 | 44 | 60 | 68
  6 | 24 |    | 56 | 61
 15 | 22 | 34 | 49 | 63
  2 | 29 | 33 | 55 | 72
~ % ruby bingo.rb
  B |  I |  N |  G |  O
  5 | 22 | 32 | 46 | 62
  4 | 24 | 44 | 52 | 75
  2 | 26 |    | 50 | 73
 15 | 17 | 35 | 51 | 69
 12 | 20 | 40 | 55 | 65

オブジェクト指向実践ガイドを読んでいて、コードを書きたくなったので書いてみました。 実際に書くと難しいです。
悩んだ点は

  • クラスを分ける必要性
  • dimentional_number_arrayメソッドはどちらのクラスにおくべきか
  • Bingoクラスのコンストラクタで@dimentional_number_array = Number.new.dimentional_number_array(インスタンス変数)を作成したが、
    • メソッド内でローカル変数としてとるべきか
    • コンストラクタで引数でとるべきか まだまだなので、アウトプットすべし!

GitHubでリポジトリ作成時のコマンドについて

リポジトリ作成時のコマンドでわからないことがあったので調べました。

echo "# sample2" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:OOOO/sample.git
git push -u origin main
  • git branch -M main

-m-Mも違いはない
git branch -m <new branchname> -m、もしくは、--moveオプション。 現在チェックアウトしているブランチ名をに変更する。 git branch -m で変更元を指定することもできる。

以下2つは同じ意味

git branch -M main
git branch -M $(git rev-parse --abbrev-ref HEAD) main

git rev-parse --abbrev-ref HEADは今いるブランチ名を表示

git rev-parse --abbrev-ref HEAD
master

masterがmainに変更されたということ

% git branch -m main
% git rev-parse --abbrev-ref HEAD
main
  • git push -u origin main

  • オプション-uについて 今回対象とするブランチを上流ブランチとして設定する(一度指定すると次回以降も対象となる) だから初回のプッシュで-uをつける

  • originとは

    リモートリポジトリのアクセス先(URL)に対してGitがデフォルトでつける名前です。

git remote add origin git@github.com:OOOO/sample.git

この設定を行うことで、リモートリポジトリに対してpushやpullができるようになります。