【書籍】地頭力を鍛える 問題解決に活かす「フェルミ推定」

地頭力の定義

地頭力が高いとは、以下の3つのポイントを抑えている人

  1. 仮説思考力
  2. フレームワーク思考力
  3. 抽象化思考力

    仮説思考力

    仮説思考力とは

    仮説思考力とは,以下の3点である.
    少ない情報から仮説を構築し
    常にその仮説を最終目的として意識し
    情報の精度と共に,仮説を修正しつつ,最終結論に至る
    このような考え方に至ることで,最終目的まで効率的に到達できる.

    ポイント

    この思考に至るポイントとして,以下の3点を意識することが重要である.
    少ない情報からでも仮説を構築する姿勢
    前提条件を設定し先に進む
    時間を決めてとにかく結論を出す

    イメージ

    仮説思考を行う上でのイメージは,常に「向こう側」(ゴール,終わり,目的,相手)から考えることである.

    f:id:k12si:20200218222320p:plain

    フレームワーク思考力

    フレームワーク思考力とは,以下の2点である.
    事象の全体像を高所から俯瞰し
    最適な切り口で切断し,断面をさらに分解する
    最適な切り口と言うのは,問題解決における切り口である.そして,その切り口から解答を導き出すために,問題をさらに細分化するといったニュアンスである.
    このような考え方に至ることで,「思考の癖を排除 → ディスコミュニケーションを回避」でき,「問題のボトルネック」を認識できる.

    ポイント

    この思考に至るポイントとして,以下の5点を意識することが重要である.
    「全体」→「部分」への視点移動(ズームイン)
    切断の「切り口」の選択
    分類(「切り口」を事象に分解)
    因数分解(事象発生の要因に分解)
    ボトルネック思考

    イメージ

    フレームワーク思考を行う上でのイメージは,問題を「全体」→「部分」へとパズルを分解していくニュアンス
    f:id:k12si:20200218224658p:plain

    抽象化思考力

    抽象化思考力とは,以下の3点である.
    対象の最大の特徴を抽出し,単純化して
    一般解を導き出して
    再び具体化して,個別解を導く
    このような考え方に至ることで,問題解決の応用範囲を広げることができる.

    ポイント

    この思考に至るポイントとして,以下の3点を意識することが重要である.
    モデル化
    枝葉の切り捨て
    アナロジー

    イメージ

    抽象化思考を行う上でのイメージは,逆U字
    f:id:k12si:20200218230119p:plain

フェルミ推定により鍛える

上記3つの思考力を鍛える効果的な手法に「フェルミ推定」というものがある.例えば以下のような問題である.

「日本全国に電柱は何本存在する?」

この容易には算出困難な問題に対する解答アプローチこそが,上記3つの「力」をフル活用したものとなり,地頭力を鍛えるための訓練となる. この際,「フェルミ推定」における解答を導くプロセスを意識しないと意味がない.そのプロセスは以下の4ステップでる.

  1. アプローチ設定
  2. モデル分解
  3. 計算実行
  4. 現実性検証

TO DO

  • 就寝前にフェルミ推定を1問解く
  • 思考する前に、全体俯瞰する意識を持つ
  • 目次から考える

【書籍】学びを結果に変えるアウトプット大全

読むに至った経緯

1年前はブログを毎日更新していた。その日学んだことの整理や、「わかった」と思い込んでいたこと、自分の中で論理が不明瞭なことを潰すことができ、アウトプットの恩恵を実感していた。しかし、日に日に更新することが苦になり、どうすれば続けることができるのかを求めるきっかけとして手に取った。

目的

  • アウトプットを持続するコツ
  • モチベーション向上
  • アウトプットの方法を学ぶ

学んだこと

RULE

  • 成長はアウトプットにのみ比例
    インプットは脳内世界が変化し、アウトプットは現実世界が変化するため
  • 2週間以内に3回のアウトプット
    海馬(仮記憶)から側頭葉(長期記憶)に記憶を移すには、海馬で一時保存される2週間の間に3回その情報を使い重要な情報であると認識させる
  • インプット:アウトプット=3:7
    インプットの2倍近くの時間をアウトプットに割く

TALK

  • 事実+意見(感想)
    何かを発信する時は上記を意識することで価値が生まれる。さらに感想を述べるだけで、脳が活性化し記憶力が向上する。
  • 明るく、元気に、笑顔で、ポジティブに
    人は言語的コミュニケーションよりも非言語的コミュニケーションを重視することが「メラビアンの法則」で立証されている。「何を話すか」よりも「どう話すか」が時として重要なこともある。
  • 議論と感情を切り離す
    議論とは「共通の目的」を持って行われる。つまり、憎しみや怒りが残ることはおかしい。「議論」と「感情」は切り離すべき。

WRITE

  • 書くことは記憶に残りやすい
    脳の中枢を刺激→脳全体を活性化
  • 脳は同時に3つのことは処理できない
    逐一書き出して、脳の3つのトレイを空にする
  • ボーッとする
    ボーッとすることで、デフォルトネットワークが形成され脳内整理が行われるため、何も考えない時間も大事。(常に頭を使うことは、逆に脳が退化する
  • フォーマット化
    これは本書に一貫して言えることだが、できるだけアウトプットする際の手順として、構成や大枠から考えることが重要。こうすることでアウトプットの敷居も下がる。
  • 目標の立て方
    1. 実現にはちょっと難しい目標を設定
    2. 期限をつける
    3. TO DOに落とし込む
    4. 客観的に評価できるようにする(↑のこと)
    5. 小さな目標に分割する

DO

  • 行動する
    インプット→アウトプット+DO→フィードバック
    アウトプットしても行動が伴わないと自己成長はない
  • 教えることが最上のアウトプット
    フィードバックが同時に行えるため
  • チャレンジ領域の見極めが大事
    ちょい難目標を設定し、そのサイクルを回していくことが大事。ドーパミンが分泌され楽しみながら学習できる。難易度が高すぎる目標はやる気がなくなる。
  • やる気は「まず、始める」ことで出てくる
    脳の側坐核が刺激され作業興奮が湧き出てくる(とりあえず5分間集中!)
  • トライ&エラーを繰り返す
  • ワクワクする方、最初に思い浮かんだ方を5秒で決断
    上記を選択した方が、ドーパミンが分泌され、結果的に後から湧いてきた選択肢よりも成功率が高い。(後から湧いてきた選択肢は大抵、打算的な選択)
  • 「30点の完成品」を磨き上げる 最初から100点を目指すよりも、30点をフィードバックにより100点にする方が効率的。
  • 7時間睡眠 6時間未満の睡眠では記憶に定着しづらい。

TO DO

  • 23時就寝6時起床
  • 概要把握は見開き1ページに手書き
  • 30点を意識する

Interpreterパターン

今回以下の技術書を読みました.

f:id:k12si:20200114202047p:plain

上記の【23章】Interpreterパターンについて解説します.

インタプリタパターンとは

ミニ言語の文法規則で記述された「ミニ・プログラム」をプログラミング言語で解析し,言語の文法をオブジェクトとして表現するパターン

ミニ言語とは

ドメイン固有言語のこと

ミニ言語プログラムとは

ミニ言語の文法定義で記述された「命令」

Interpreterパターンの例を具体的に1つ挙げると,

SQLの文法規則で記述されたクエリJavaで解析し,SELECT文などをオブジェクトとして表現するパターン」

となる.

疑問

なぜ,「特定の処理」をするために,わざわざ「ドメイン固有言語」で命令を発行する必要があるのでしょうか.
「1クッション新たな定義言語を挟まず,実行環境のプログラミング言語で直接命令を解釈すればいいのでは?」と思いました.
本書のSampleプログラムの実行結果は以下のようになっています. f:id:k12si:20200115001836p:plain

text = <ミニ・プログラム(命令)>
node = <解釈後の出力結果>

特に一番下の結果は,解釈後の出力結果にどんなメリットがあるのかわかりませんでした.

メリット

そもそもドメイン固有言語で記述すること自体に以下のメリットがあります.

  • ドメインに特化した言語実装により,高効率で問題解決が可能

さらに,1つのトークン(SQLでいうSELECT文といった単一の命令のこと)の処理を1つのクラスで定義するため

また,各種トークンの処理定義をクラスに落とし込み,命令(クエリ)を別ファイルに切り出すことで

  • 命令を設定ファイルや外部入力から得ることで動的な振る舞いを実現することが可能

また,トークンとは単なる字句です.(SELECTとは単なる文字)
しかし,このトークンがクラスで表現されることでオブジェクトとなります.
命令とは,トークンの羅列であり,すなわちオブジェクトの羅列へと落とし込むことができます.さらに,オブジェクトとはメンバ関数を保持し,メンバ関数は「振る舞い」を意味します.
つまり,「単なる字句の羅列(命令)」がInterpreterパターンを利用することで,オブジェクト指向をうまく利用した,「振る舞いの連鎖」へと解釈,実行することができます.

上記解釈は,以下のサイトを参考にさせていただきました. http://marupeke296.com/DP_Interpreter.html

活用事例

時間あるときに考える!!

まとめ

  • interpreterパターンとは何らかの文法規則で記述された命令を解析し,言語の文法をオブジェクトで表現するパターン

  • ドメインに特化した言語定義は高効率

  • トークンをクラスで表現することで柔軟性や再利用性が高まる

【書籍】学び効率が最大化するインプット大全

本を読むに至った経緯

  • 友人が本書籍を購入していた
  • 日々の生活で,学んだり,聞いたりしたことをすぐに忘れているという自覚があり改善したいと思っていた
  • 年末年始暇

目的

  • 忘れにくいインプット術を学ぶ
  • 意識向上

学んだこと

アウトプットを意識したインプット

インプットする際,「後でアプトプットをする」ということを意識することで,心理的プレッシャーがかかる.これにより脳からノルアドレナリンが分泌される.このノルアドレナリンが分泌されると集中力記憶力思考力判断力が高まり圧倒的に記憶に残りやすくなる.

感情を伴うインプット

喜怒哀楽を伴って分泌される脳内物質には記憶を増強する作用がある.

脳内物質 感情
アドレナリン 恐怖,怒り
ノルアドレナリン 悲しみ,緊張,不安
ドーパミン 楽しい,嬉しい
エンドルフィン 感謝,楽しい
オキシトシン 愛,親切

全体→部分

これは本を読む際に,効率的な読み方として紹介されていました.

  1. 本を読む前に「なぜこの本を読むのか?」といった目的をはっきりさせる.
  2. 「目次」と各章の「はじめ」と「まとめ」をパラパラと読んでその本の大まかな構成や内容を把握.(パラパラ読み)
  3. 1ページ目からじっくり読んでいく.

ざっくりとその本の構成や内容を把握しているため,読むスピード,読み込める深さが格段に違うと言ったものです.
そもそも脳の仕組み的に,「全体」から「部分」へと理解していくことが良いとされているので記憶に残りやすい.

TODO

  • インプット前の15分は音楽を聞いてドーパミンを分泌
  • よく観察し,「なぜ?」を自問自答 → トレンドに敏感になるため
  • 本を読む前に,「キーワード」,「方向性」,「期限」,「ゴール」を意識
  • flierで本の要約を読んでから,読み始める
  • 就寝前には本を読む

平成27年度ネットワークスペシャリスト試験 午後Ⅰ(問1)

自分用メモ

 

問題:https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2015h27_2/2015h27a_nw_pm1_qs.pdf

 

シングルサインオン(SSO)に関する問題

 

構成は以下

f:id:k12si:20191009002747p:plain

 

各サーバのドメインは以下

f:id:k12si:20191009002902p:plain

 

問題

設問1

ア:リバースプロキシ

SSOには以下2種類の設定方法がある.

①SSOを利用するサーバにエージェントをインストールし,SSOサーバにリダイレクトさせることで認証を行うエージェント方式

②サーバ接続にリバースプロキシを導入することで,リバースプロキシ内で認証を行うリバースプロキシ方式

 

イ:リダイレクト

SSOに①方式を用いたため,まずWebサーバにアクセス要求を行うと,エージェントはアクセスチケット(Cookie)を確認する.
この段階ではアクセスチケットが設定されていないため,SSOサーバへリダイレクトさせクライアントに認証処理を促している.

 

ウ:Set-Cookie

HTTPヘッダにおけるSet-Cookieヘッダには様々な属性が存在する.
そのうちの一つがDomain属性である.
Domain属性:Cookieの適用対象となるドメインを設定

ついでに,設問3の(1)の解説もここで記載.

今回,A社の全サーバへのアクセスにSSOでの一括認証機能を実装したいということなので,

各サーバへのアクセス全てにCookie情報を付与したい.

つまり,各サーバのドメインにおいて共通している部分である「a-sha.example.jp」をDomain属性に設定すればok.

以下がとてもわかりやすく参考とさせていただきました.
参考:https://qiita.com/mogulla3/items/189c99c87a0fc827520e

 

エ:内部DNS 

SSOサーバへのアクセス時,一旦LBにリクエストを集めたい.

つまり,SSOサーバへのドメインアクセス時(sso.a-sha.example.jp),VIPへと名前解決を行いたい.

従って,DNSサーバにおけるAレコードを変更すればいいとわかる.

 

オ:ループバック

LBにVIPアドレスを付与したが,SSOサーバ1,2についてもVIPをそのまま利用する.

ここでIPアドレスとは本来NICに1つ設定できるものであり,自由にIPを後から設定できる物ではない.

そこで物理NICではなく仮想NICであるループバックインタフェースにVIPを設定することで,LBから送信されたVIP宛ての転送リクエストパケットを受信することを可能としている.

設問2

⑥でのアクセスチケットはSSOにリダイレクト後,認証作業をした後に発行されたものである.従って⑤が答え.

設問3

(1)省略

(2)CookieにSecure属性をつける

CookieにはSecure属性というものが存在する.

Secure属性:HTTPSで通信している場合にのみCookieを送信する

この属性の設定により,上記サーバ以外による意図しないコネクションでのHTTP通信時におけるCookieの流出を避けることが可能.

設問4

(1)SYNパケットにはレイヤ7情報が含まれていないから

(2)GARP(Gratuitous ARP)

(3)VIPアドレスに対するARPリクエストに応答しないように設定する

VIPへのリクエストはLBに集まるべきである.従って,SSOサーバに設定したVIPがARPに反応してしまっては困るため上記のような設定を行う.

これにより,クライアント側からのリクエストは一旦LBに集約される.

ns-3環境の構築

研究でns3を利用することになったので,仮想環境の設定から,ns3の環境構築までをざっとメモ

仮想環境

ns-3|環境構築

  • 事前準備:Installation - Nsnam
  • ns-3コードのインストール
    • 方法1:wgetでコードをダウンロード
      $ wget https://www.nsnam.org/release/ns-allinone-3.29.tar.bz2
      $ tar xjf ns-allinone-3.29.tar.bz2
    • 方法2:gitでclone
  • リポジトリ作成(Git)

    ビルド

  • waf設定
$ ./waf clean #wafのビルド設定をリセットする
$ ./waf configure --build-profile=debug --enable-examples --enable-tests --out=build/debug
  • wafのビルド設定の確認
$ ./waf --check-profile #プロファイルの設定確認(debug, optimized, release)
$ ./waf --check-config #ns3の設定全般を表示(オプションの有無)
  • wafでビルド
$ ./waf (build) #省略可能
  • テストコード
$ ./test.py
$ ./waf --run hello-simulator
$ ./waf
$ ./waf --run scratch/<スクリプト名> #scratchディレクトリ配下に保存

ns-3|コマンド

  • wafのオプション確認
$ ./waf --help

NetAnim3.108

  • サンプル(ns-3.29/src/netanim/examples/dumbbell-animation.cc)をビルド
$ ./waf --run "dumbbell-animation --nLeftLeaf=5 --nRightLeaf=5 --animFile=dumbbell.xml"
  • netanim-3.108ディレクトリ移動(ns-allinone-3.29に同封されている)
$ cd workspace/ns-allinone-3.29/netanim-3.108
  • NetAnim起動
$ ./NetAnim
  • ファイルボタンをクリックし,XMLトレースファイルを選択

ns-3|リンクまとめ

OFSwitch13|設定

ns-3へOpenFlow1.3を利用するためのモジュールを追加

  • 事前準備
$ sudo apt-get install build-essential gcc g++ python git mercurial unzip cmake
$ sudo apt-get install pkg-config autoconf libtool libboost-dev
  • OFSwitch13モジュール(ofswitch13)のダウンロード
$ cd ns-3.29/src
$ git clone --recurse-submodules https://github.com/ljerezchaves/ofswitch13.git
  • ofswitch13を最新に変更
$ cd ofswitch13
$ git checkout 4.0.0 && git submodule update --recursive
$ cd lib/ofsoftswitch13
$ ./boot.sh
$ ./configure --enable-ns3-lib
$ make
  • ofsoftswitch13を利用するために、ns-3の一部モジュールに受信部を追加(CsmaNetDevice, VirtualNetDevice)
$ cd ../../../../
$ patch -p1 < src/ofswitch13/utils/ofswitch13-src-3_29.patch
$ patch -p1 < src/ofswitch13/utils/ofswitch13-doc-3_29.patch
  • ns-3の設定確認
$ ./waf configure
  • ns-3ビルド
$ ./waf

【モジュール分割】図解で分かるジャクソン法

こんばんは。

 

今回は、応用情報H28秋午後

問8「情報システム」で出てきたジャクソン法について勉強したことをまとめていきます。

 

問題は「モジュール分割」についてのお話でした。

 

いろいろ調べていて、モジュール分割を意識するのはとても大事だと感じました。

 

さて、標題のジャクソン法の説明の前に以下について触れておきたいと思います。

  • なぜモジュール分割を行うのか
  • モジュール分割手法って何があるの
  • モジュール分割でよく聞く関数型プログラミングってなに

上記に触れた後、ジャクソン法についてまとめたいと思います。

なぜモジュール分割を行うのか

ソフトウェア設計を考える際、機能をいくつかの単位に分割します。

 

一般的には以下のように階層的に分割されます。

「システム」=>「サブシステム」=>「プログラム」=>「モジュール」

 

ここで重要なことは、大きな粒度 → 小さな粒度 へと問題を落とし込んでいくことです。

これは以下のようなメリットがあるためです。

  • 作業の分担化
  • 問題の複雑さを減らす
  • コードの再利用化
  • 拡張性や修正が行いやすい

モジュール分割手法って何があるの

以下の2種類の考え方がります。

  • データの流れで分割
  • データの構造で分割

データの流れで分割

データの入力(Source)、変換(Transformation)、出力(Sink:吸収)の3つに分割する手法。

これらの分割したモジュールを制御モジュールによって操作します。

  • TR分割

データの種類とその処理内容に応じて分割する方式。

  • 共通機能分割

共通して行われる処理をモジュールとして切り出す方式。

データの構造で分割

  • ジャクソン分割

入出力データの構造からプログラムの構造を決定していく方式。

  • ワーニエ分割

入力データの構造を分析してプログラムの構造を決定していく方式。

モジュール分割でよく聞く関数型プログラミングってなに

まず、プログラムの書き方には(たぶん)2種類存在します。

以下にそれぞれの特徴をあげますが、

にわかなので間違っているかもしれないです。m(_ _)m

以下の例では、どちらもRubyで記述しており、

商品合計を表す関数を実装しています。

命令(手続き)型プログラミング

# 商品リスト
item_list = [
    {
        name: "hogehoge",
        price: 100
    },
    {
        name: "hugahuga",
        price: 200
    }
]

# 商品合計計算関数
def price_counter(item_list)
    
    sum_price = 0   # 商品合計
    
    item_list.each do |item|
        sum_price += item[:price]
    end
    
    return sum_price
end

p price_counter item_list

 

上記コードでは、商品合計をsum_priceといった状態に格納しています。

 

ループ処理によって sum_priceが上書きされていきます。

 

命令型プログラミングとは,要するに

プログラムの状態を表す変数を、代入命令で変更していく

といったニュアンスです。

関数型プログラミング

# 商品リスト
item_list = [
    {
        name: "hogehoge",
        price: 100
    },
    {
        name: "hugahuga",
        price: 200
    }
]

# 商品合計計算関数
def price_counter(item_list=[])
    if item_list.length == 0
        return 0
    else
        return item_list.pop[:price] + price_counter(item_list)
    end
end

p price_counter item_list

 

一方こちらは、商品の合計金額がいくらかといった状態は現れません。

 

このように変数の初期化や、代入といった命令が存在しません。

 

関数型プログラミングとは、要するに

プログラムの状態を変化させない関数」を作成し、

これらを組み合わせて問題解決を行う手法です。

 

ちなみに、命令型プログラミングのように、プログラムの状態が変化することを副作用と言います。

また、副作用を持たない関数を純粋関数と呼びます。

 

前置きが長くなりました。

要するにここで言いたいこととしては、モジュール分割には

状態を変化させない関数型プログラミングとの相性が良いということです。

 

具体的には、関数型プログラミング高階関数やら遅延評価なんかがモジュール化に良い感じなようです。

 

この辺は本題ではないので参考リンクだけ以下に掲載しておきます。

 

 

さて、ここからが本題です。(いつも本題に入る手前が長い🙇‍♂️)

ジャクソン法

まず、ジャクソン法の目的は「モジュール分割」です。

 

しかし、本来の目的とは

 

プログラミングが簡単になる構造を見つけ出すこと

 

です。

 

そうです。結果的にモジュール分割に応用できるみたなことです。(たぶん笑)

 

具体的には以下のような特徴があります。

  • 入出力データ構造でプログラム分割
  • 基本,連接,選択,反復の4つの木構造でデータを表現

2つめの4つの木構造とは、具体的に以下です。

f:id:k12si:20190414015619p:plain

引用元:システム開発の方法

 

これだけ読んでもわからないと思うので、

ここからは実際にプログラミングの問題をジャクソン法に則って考えていきます。

 

作成するプログラムは以下の表示です。(以下ピラミッドと呼びます。)

f:id:k12si:20190414011231p:plain

 

ジャクソン法でプログラムの詳細設計を行うには以下の手順で考えます。

  1. 入力データ構造を、木構造で表現
  2. 出力データの構造を、木構造で表現
  3. 入力出力データ構造を元に、プログラム構造を設計

入力データ構造を、木構造で表現

まずピラミッドを作成する際、入力データのイメージを以下に示します。

f:id:k12si:20190414013840p:plain

空白や*の連続を部分という構造として捉えているのが重要です。

これを、データ構造として捉えて、木構造で表現したのが以下です。

 

f:id:k12si:20190414015420p:plain

 

出力データの構造を、木構造で表現

続いて出力データについても、入力データ同様に

データ構造に着目しながら、基本、連接、選択、繰り返しの4つの木構造で表現していきます。

 

といっても、今回の問題では、入力がそのまま出力になります。

f:id:k12si:20190414021137p:plain

入出力データ構造を元に、プログラム構造を設計

最後に、

前述で作成した「入力データ構造」と「出力データ構造」の対応関係を知り、

両者を付き合わせたデータ構造を作成します。(入力データ構造が主)

 

作成したデータ構造は以下になります。

 

f:id:k12si:20190414022510p:plain

 

この段階の構造図で、各階層の処理部分には「前処理」と「後処理」を記述するのが常のようです。

 

今回の問題では必要ないため省略しています。

 

さてさて、これでコードにすっきりと落とし込むことができます。

 

以下が上記のデータ構造をコード化したものになります。

 

/* 1段分のピラミッドを作成 */
for ( i=0; i < (行数); i++ ) {
    空白を(行数 - i)表示    /* 空白部分1 */
    *文字を(2i - 1)表示    /* *部分 */
    空白を(行数 - i)表示    /* 空白部分2 */
改行を表示 }

 

最後に参考にしたリンクを掲載しておきます。

まとめ

本日はジャクソン法の考え方についてまとめました。

 

入力データと出力データのデータ構造に着目し、

4種(基本,連接,選択,繰り返し)の木構造を用いて、

プログラミングを簡単にしていく手法。

 

参考リンクやいろいろ調べるともっと奥が深そうでした。

 

とりあえず、今回の学びから、いかにモジュール分割が大事かということが理解できた。

もっと複雑な問題にも、こういった考え方やアプローチから論理的に解決に導けそうだと感じました🙌