独り言

プログラミングの講師をしています。新人研修で扱う技術の解説と個人の技術メモ、技術書の紹介など

【JavaScript】じゃんけんゲーム

JavaScriptで作成した簡単なじゃんけんゲームです。
画像ファイルは適当なネットのフリー素材を探してご使用ください。
JavaScriptの学習、ゲーム作成の参考に。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>じゃんけんゲーム</title>
    <style>
        body {
            text-align: center;
        }
        #your-choice, #opponent-choice {
            font-size: 24px;
        }
        img.hidden {
            display: none;
        }
        main {
            display: flex;
            justify-content: space-between;
        }
        section {
            margin: 0 auto;
        }
    </style>
</head>
<body>
    <h1>じゃんけんゲーム</h1>
    <button type="button" name="btn" value="0">グー</button>
    <button type="button" name="btn" value="1">チョキ</button>
    <button type="button" name="btn" value="2">パー</button>
    <main>
        <section>
            <p>あなた</p>
            <p id="your-choice"></p>
            <img id="your-choice-img" class="hidden" src="#">
        </section>
        
        <section>
            <p>相手</p>
            <p id="opponent-choice"></p>
            <img id="opponent-choice-img" class="hidden" src="#">
        </section>

    </main>

    <hr>

    <p>結果</p>
    <p id="result"></p>
    <p>戦歴 <span id="totalNum">0</span><span id="winNum">0</span></p>

    <script>
        'use strict';

        const jankenImg = ['img/janken_gu.png', 'img/janken_choki.png', 'img/janken_pa.png'];
        const yourChoice = document.getElementById('your-choice');
        const opponentChoice = document.getElementById('opponent-choice');
        const yourImg = document.getElementById('your-choice-img');
        const opponentImg = document.getElementById('opponent-choice-img');


        const JankenDisp = function(choice, p, img) {
            img.src = jankenImg[choice];
            img.classList.remove('hidden');
            if(choice === 0) {
                p.textContent = 'グー';
                img.alt = 'グー';
            } else if (choice === 1) {
                p.textContent = 'チョキ';   
                img.alt = 'チョキ';
            } else if (choice === 2) {
                p.textContent = 'パー';   
                img.alt = 'パー';
            }
        } 

        const judge = function(yourChoice, opponentChooice) {
            let totalNum = Number(document.getElementById('totalNum').textContent);
            totalNum++;
            let winNum = Number(document.getElementById('winNum').textContent);
            let result;
            // グーの場合
            if(yourChoice === 0) {
                if (opponentChooice === 0) {
                    result = 'あいこです';
                } else if (opponentChooice === 1) {
                    result = 'あなたの勝ちです';
                    winNum++;
                } else if (opponentChooice === 2) {
                    result = 'あなたの負けです';
                }
            }
            // チョキの場合
            if(yourChoice === 1) {
                if (opponentChooice === 0) {
                    result = 'あなたの負けです';
                } else if (opponentChooice === 1) {
                    result = 'あいこです';
                } else if (opponentChooice === 2) {
                    result = 'あなたの勝ちです';
                    winNum++;
                }
            }
            // パーの場合
            if(yourChoice === 2) {
                if (opponentChooice === 0) {
                    result = 'あなたの勝ちです';
                    winNum++;
                } else if (opponentChooice === 1) {
                    result = 'あなたの負けです';
                } else if (opponentChooice === 2) {
                    result = 'あいこです';
                }
            }
            document.getElementById('totalNum').textContent = totalNum;
            document.getElementById('winNum').textContent = winNum;
            document.getElementById('result').textContent = result;

        }

        const btns = document.getElementsByName('btn');
        btns.forEach((el, key) => {
            el.addEventListener('click', function() {
                // 押したボタンの内容が表示される処理
                JankenDisp(Number(this.value), yourChoice, yourImg);

                // 相手の選択をランダムで処理
                let choiceNum = Math.floor(Math.random() * Math.floor(3));
                JankenDisp(choiceNum, opponentChoice, opponentImg);

                // 判定
                judge(Number(this.value), choiceNum)

            });
        })

        // for..ofバージョン
        // for(let btn of btns) {
        //     // ボタンを押下したときの処理
        //     btn.addEventListener('click', function() {
        //         // 押したボタンの内容が表示される処理
        //         JankenDisp(Number(this.value), yourChoice);

        //         // 相手の選択をランダムで処理
        //         let opponentChoice = Math.floor(Math.random() * Math.floor(3));
        //         JankenDisp(opponentChoice, opponentChoice, yourImg);

        //         // 判定
        //         judge(Number(this.value), opponentChoice, opponentImg)

        //     });
        // }

    </script>
</body>
</html>

【Java】【AWS】Amazon EC2でJavaのWebアプリケーション動作環境を構築してデプロイするまで

クラウド上にJavaによるWebアプリケーションの動作環境を構築する手順です。
AWSAmazon EC2を使用し、マシンイメージはAmazon Linux 2 を利用します。
DBはPostgreSQLを使用する前提とします。

解説する内容は以下の項目。
インスタンスの作成までに関する手順とSSH接続する手順は省略します。

  • ロケールの変更
  • PostgreSQLのインストール
  • Javaのインストール
  • ApacheTomcatのインストール
  • GitとMavenのインストール
  • Webアプリケーションのデプロイ
  • Gitを活用したデプロイ方法

ロケールの変更

参考サイト
Amazon LinuxのデフォルトのロケールはENになっている。
Spring Bootをでメッセージリソースを使う場合、デフォルトでen用のファイルを読み込んでしまう。
ファイルがない場合はエラーになるので、日本に設定しておく。

# ロケールの確認
$ localectl status
# ロケール変更
localectl set-locale LANG=ja_JP.eucjp
# 変更されたか確認
$ localectl status

PostgreSQLのインストール

ここではEC2インスタンスPostgreSQLをインストールして外部から接続できるようにする手順を解説します。
該当のEC2インスタンスSSH接続されていることを前提とします。

参考サイト

1. リポジトリの更新

まずはリポジトリを更新する。 デフォルトの状態でPosgreSQLをインストールするとバージョンが9.2なので(2020/09時点)最新バージョンがインストールできるようにリポジトリ更新します。

$ wget https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
$ sudo rpm -Uvh --nodeps pgdg-redhat-repo-latest.noarch.rpm
$ sudo sed --in-place -e "s/\$releasever/7/g" /etc/yum.repos.d/pgdg-redhat-all.repo

2.PostgreSQLのインストールと環境設定

まずはインストールしてサービスの起動

# postgreSQLのインストール
$ sudo yum -y install postgresql12-server
# データベース初期化
$ sudo /usr/pgsql-12/bin/postgresql-12-setup initdb
# サービス自動起動設定
$ sudo systemctl enable postgresql-12
# サービスの起動
$ sudo systemctl start postgresql-12.service

デフォルトではOSユーザーでログインする設定なので、postgresユーザーにパスワードを与えてログインする。
(PostgreSQLをインストールすると自動でpostgresユーザーが作成される)

# postgresのパスワード変更(ここではpasswordとする)
$ sudo passwd postgres
⇒password

# ユーザーを切り替え
$ su - postgres
password ⇒ password

# postgreSQLへログイン
$ psql

PostgreSQL内のpostgresユーザーのパスワードを変更しておく。
デフォルトだとパスワードは設定されていない。

# postgreSQL内のpostgreユーザーのパスワード変更(ここではpasswordとする)
alter user postgres with password 'password';

# postgresqlログアウト
\q

postgresqlからログアウトしてec2-userに戻ったら、外部からOSのユーザー以外でもログインできるように設定ファイルを変更する。

# ec2-userに戻る(postgreユーザーになっているため)
$ exit

# 設定ファイルの変更
# 外部からのアクセスできるようにする
$ sudo vi /var/lib/pgsql/12/data/postgresql.conf

# listen_address = 'localhost'
⇓
listen_address = '*'

# 設定ファイルの変更
# 外部からのpostgreSQLユーザーのパスワードでアクセスできるようにする
$ sudo vi /var/lib/pgsql/12/data/pg_hba.conf

# IPv4 local conecctions:
host  all  all  127.0.0.1/32  ident
⇓
host  all  all  0.0.0.0/0  md5

# サービス再起動
$ sudo systemctl restart postgresql-12.service

外部からの接続を確認する。
コマンドプロンプトpowershell等から

psql -h <パブリックDNS> -p 5432 -U postgres -d postgres

その後パスワード(ここではpassword)を入力して接続できることを確認する。


Javaのインストール

Java環境のインストール方法です。
AmazonのOpenJDK(amazon-corretto)をインストールします。

参考サイト

# JDKインストール
$ sudo yum -y install java-11-amazon-corretto
# javac バージョン確認
$ javac --version
# java バージョン確認
$ java --version

ApacheTomcatのインストール

ApacheTomcatのインストールに関しては以下のサイトを参考に。
参考サイト

ちなみに、Spring Bootアプリケーションをデプロイする場合はビルドされたファイルにTomcatが含まれるため、全グループがSpring Bootアプリケーションを前提に開発を進める場合はこの手順は省略しても問題ありません。

Apacheインストール

# インストール
$ sudo yum install -y httpd
# 確認
$ httpd -v
# 自動起動設定
$ sudo systemctl enable httpd.service
# 起動
$ sudo systemctl start httpd.service
# 停止
$ sudo systemctl stop httpd.service

Tomcatインストール

ダウンロードするバージョンは
公式サイト
から確認

# ユーザー作成
$ sudo useradd -s /sbin/nologin tomcat

# tomcatダウンロード
$ cd ~
$ wget https://downloads.apache.org/tomcat/tomcat-9/v9.0.38/bin/apache-tomcat-9.0.38.tar.gz

# 解凍して配置
$ tar -xzvf ~/apache-tomcat-9.0.38.tar.gz
$ sudo mv ~/apache-tomcat-9.0.38 /opt
$ sudo chown -R tomcat:tomcat /opt/apache-tomcat-9.0.38

# シンボリックリンクの作成
$ sudo ln -s /opt/apache-tomcat-9.0.38 /opt/apache-tomcat
$ sudo chown -h tomcat:tomcat /opt/apache-tomcat

# ログのシンボリックリンク作成
$ sudo ln -s /opt/apache-tomcat/logs /var/log/tomcat
$ sudo chown -h tomcat:tomcat /var/log/tomcat

# TomcatをOSにサービスとして登録する為、ルート権限でUnitを作成
$ sudo vi /usr/lib/systemd/system/tomcat.service

tomcat.service

[Unit]
Description=Apache Tomcat Web Application Container
After=syslog.target network.target

[Service]
Type=oneshot
PIDFile=/opt/apache-tomcat/tomcat.pid
RemainAfterExit=yes
#EnvironmentFile=/etc/tomcat/tomcat.conf
#Environment="NAME="
#EnvironmentFile=-/etc/sysconfig/tomcat
ExecStart=/opt/apache-tomcat/bin/startup.sh
ExecStop=/opt/apache-tomcat/bin/shutdown.sh
ExecReStart=/opt/apache-tomcat/bin/shutdown.sh;/opt/apache-tomcat/bin/startup.sh
SuccessExitStatus=143
User=tomcat
Group=tomcat

[Install]
WantedBy=multi-user.target
# 自動起動設定
$ sudo systemctl enable tomcat.service
# システム起動
# Apacheを先に起動
$ sudo systemctl start httpd.service
$ sudo systemctl start tomcat.service

# システム停止
$ sudo systemctl stop tomcat.service

ブラウザから http://<パブリックDNS>:8080 でTomcatのトップページにアクセスできることを確認する。


http://ec2-18-182-18-43.ap-northeast-1.compute.amazonaws.com:8080/

※Spring Bootアプリケーションを起動したい場合は、Tomcatが起動しているとポート番号が重複してエラーになるので注意。


GitとMavenのインストール

GitとMavenを使ってデプロイすることも可能なので、それ用にインストールしておいても良いかも

Gitのインストール

# git インストール
$ sudo yum -y install git 
# バージョン確認
$ git version

Mavenのインストール

参考サイト

mavenの最新バージョンのリンクはこちらから

# ダウンロード
$ cd ~
$ sudo wget https://ftp.jaist.ac.jp/pub/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz

# 展開&配置
$ sudo tar -xzvf apache-maven-3.6.3-bin.tar.gz
$ sudo mv apache-maven-3.6.3 /opt/
# シンボリックリンク作成
$ sudo ln -s /opt/apache-maven-3.6.3 /opt/apache-maven
# PATHの追加
$ vi .bash_profile
PATH=$PATH:$HOME/.local/bin:$HOME/bin
⇓
MVN_HOME=/opt/apache-maven
PATH=$MVN_HOME/bin:$PATH:$HOME/.local/bin:$HOME/bin
# PATHを通す
$ source .bash_profile
# Mavenバージョン確認
$ mvn --version

Webアプリケーションのデプロイ方法

デプロイとは開発環境のプログラムをアプリケーションを動作させる本番環境に反映させることをいいます。

Spring Bootを使用した場合と使用しない場合で方法が異なります。

Spring Bootアプリケーションの場合(JSPを使用していない場合)

参考サイト

プロジェクトをビルドしてjarファイルを作成する
Eclipseで対象のSpring Bootプロジェクトを右クリック ⇒ 実行 ⇒ Maven install を実行。
ビルドが成功したらtarget配下にjarファイルができる。

※環境によってはエラーが出ることがある。

java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test

その時はsrc/test/java配下にあるテストクラスにある@SpringBootTestアノテーションに引数を追加する。

// クラス名は@SpringBootApplicationがついているクラス
@SpringBootTest(classes = {TaskFrameworkApplication.class})

これでエラーが解消する場合がある。

jarファイルを転送する
scpコマンドなどを使用してjarファイルをEC2インスタンスに転送する。

コマンドプロンプトなどから

scp -i pemファイル "jarファイルのパス" ユーザー名@パブリックDNS:転送先のパス

を実行する


デスクトップのjarファイルをec2-userのホームディレクトリに転送する

scp -i nihonbasib_20200915.pem "C:\Users\admin\Desktop\demo-0.0.1-SNAPSHOT.jar" ec2-user@ec2-18-182-18-43.ap-northeast-1.compute.amazonaws.com:~/

Webアプリケーションを実行する EC2インスタンスSSH接続し

java -jar 転送されたjarファイル

を実行するとSpringBootアプリケーションが起動する。

ブラウザからアクセスして動作を確かめる http://パブリックDNS:8080/マッピングしているパス

プログラムを停止したい場合
Ctrl + CでTomcatを停止することができます。
ただしサーバーを停止してもプロセスが残っている場合があります。
その場合はpsコマンドでプロセスIDを確認し、killコマンドで終了させる。

# プロセスの確認
$ ps a
# 出力結果からjavaアプリケーションのPIDを確認
# killコマンドでプロセスを削除
$ kill PID

Spring Bootアプリケーションの場合(JSPを使用している場合)

参考サイト JSPを使用する場合(アプリケーションにWEB-INFフォルダが存在している場合)は、jarファイルによるデプロイができない。
jarファイルとして作成した場合、WEB-INFフォルダが作成されない。
warファイルとして作成し、Tomcat上でデプロイする必要がある。
ビルドの方法は変わらない。

pom.xmlに以下を追加

<packaging>war</packaging>

書く場所はproject要素の直下。
propertiesやdependenciesなどと同じ階層に書く。
Eclipseの場合はプロジェクト作成時にビルドがjarかwarかを選択できるので、そこでwarを選択しておけば勝手に追記されるはず。

また、warファイルでデプロイする場合は外部のTomcatを使ってデプロイするため、warファイルにTomcatを含める必要がなくなる。
デフォルトだとTomcatを含めてしまうので、pom.xmlで省くように設定する。

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
</dependency>

scopeをprovidedにすれば良い。
warファイルのデプロイ方法は次節の動的Webアプリケーションの場合で解説します。

動的Webアプリケーションの場合

Spring Bootを使用せずにJSP/Servletのみで作成した場合
参考サイト

warファイルを作成する Eclipseからプロジェクトを右クリック ⇒ エクスポート ⇒ warファイルを選択。
出力先を指定してwarファイルを出力します。

warファイルを転送する scpコマンドなどでwarファイルをEC2インスタンスに転送します。

scp -i pemファイル "warファイルのパス" ec2-user@パブリックDNS:~/ 

scp -i nihonbasib_20200915.pem "C:\Users\admin\Desktop\demo.war" ec2-user@ec2-18-182-18-43.ap-northeast-1.compute.amazonaws.com:~/

※ユーザー名(ec2-user)を書き忘れるとPermissionのエラーが出る。
パブリックDNSだけコピーして実行しようとするとエラーになるので注意。

Tomcatの起動とwarファイルの展開 EC2インスタンスssh接続し、転送されたwarファイルを
tomcatがインストールされたディレクトリ/webapps
に配置します。
tomcatは /opt/apache-tomcat
にインストールされている想定です。
インストールされていない場合は講師に確認してください。

$ sudo cp warファイル /opt/apache-tomcat/webapps
# Apacheを起動
$ sudo systemctl start httpd.service
# Tomcatを起動
$ sudo systemctl start tomcat.service

Tomcatの起動に成功すれば、webapps配下でwarファイルが展開されます。
展開されているかどうかはlsコマンドなどで確認してください。

$ sudo ls /opt/apache-tomcat/webapps/

ブラウザから http://パブリックDNS:8080/コンテキストルート
でアクセスして実行結果を確認する。


Gitを活用したデプロイ方法

Eclipseからjarファイルやwarファイルを作成してEC2上に転送するのではなく、直接EC2インスタンス上でjarファイルやwarファイルを作成することも可能です。

前提条件
* EC2インスタンスにGitがインストールされていること
* EC2インスタンスMavenがインストールされていること(Spring Bootを使用する場合)
* GitHub, GitLabなどのホスティングサービスにリモートリポジトリが作成されていること ※.gitignoreでクラスファイルなどが除外されていることを確認して下さい。

# Gitがインストールされていることの確認
$ git version

# 初期設定をしておく
# ユーザー名の設定
git config --global user.name "ユーザー名"
# メールアドレスの設定
git config --global user.email "メールアドレス"

# リモートリポジトリをクローンする
$ git clone リモートリポジトリのURL

# 作業ディレクトリ移動
$ cd クローンされたプロジェクト

Spring Bootの場合

プロジェクトのディレクトリ配下にpom.xmlがあることを確認する。
ビルドする際にpom.xmlがないとうまくいかない。

プロジェクトのビルド

# Mavenがインストールされていることの確認
$ mvn --version
# ビルド
$ mvn package spring-boot:repackage

ビルドが成功すればtargetディレクトリが作成され、中にjarファイルが出来上がります。

Webアプリケーションを実行する jarファイルを使ってアプリケーションを起動します。

java -jar 転送されたjarファイル

ブラウザからアクセスして動作を確かめる http://パブリックDNS:8080/マッピングしているパス

プログラムを停止したい場合
Ctrl + CでTomcatを停止することができます。
ただしサーバーを停止してもプロセスが残っている場合があります。
その場合はpsコマンドでプロセスIDを確認し、killコマンドで終了させる。

# プロセスの確認
$ ps a
# 出力結果からjavaアプリケーションのPIDを確認
# killコマンドでプロセスを削除
$ kill PID

動的Webアプリケーションの場合

参考サイト 「src」と「WebContent」ディレクトリがあるディレクトリに移動しておく。

# ライブラリ用ディレクトリ作成
$ mkdir lib
# servlet-api.jarを移動しておく
$ sudo cp /opt/apache-tomcat/lib/servlet-api.jar lib
# ソースファイルをコンパイルする
$ javac -sourcepath src -classpath lib/* -d WebContent/WEB-INF/classes src/example/*

# warファイルを作成
$ jar cvf webtest.war -C WebContent .

Tomcatの起動とwarファイルの展開 warファイルを
tomcatがインストールされたディレクトリ/webapps
に配置します。
tomcatは /opt/apache-tomcat
にインストールされている想定です。
インストールされていない場合は講師に確認してください。

$ sudo cp warファイル /opt/apache-tomcat/webapps
# Apacheを起動
$ sudo systemctl start httpd.service
# Tomcatを起動
$ sudo systemctl start tomcat.service

Tomcatの起動に成功すれば、webapps配下でwarファイルが展開されます。
展開されているかどうかはlsコマンドなどで確認してください。

$ sudo ls /opt/apache-tomcat/webapps/

ブラウザから http://パブリックDNS:8080/コンテキストルート
でアクセスして実行結果を確認する。

【PowerShell】PowerPintのプロパティのタイトルを一括で変更する

PowerPointExcelなどのOffice製品では、プロパティでタイトルを設定することができます。
PowerPointだけを使っている場合にはあまり意識しなくても良い部分ですが、PDFにエクスポートする時ファイルのタイトルとしてタブに表示されます。
ファイル名と同じにしておくと無難ですが、ファイルがたくさんあると一つ一つ変更するのは面倒です。
大量にあるPowerPointのファイルのタイトルをファイル名に変更してPDFとして出力するPowerShellスクリプトです。
試行錯誤した履歴も含めて。

# 最初は再帰でやろうとしたけど失敗。無限ループになる
# Function titleRename($dir) {
#    foreach($file in $dir) {
#         if ($file.Mode.Substring(0,1) -eq "d") {
#             check $file
#         } ElseIf($file.Name.Substring($file.Name.Length - 5, 5) -eq ".pptx") {
#             $ppt = New-Object -ComObject PowerPoint.Application
#             $pres = $ppt.Presentations.Open($file.FullName)
#             $pres.BuiltInDocumentProperties("title") = $pres.Name.substring(0, $pres.Name.length - 5)
#             $pres.Save()
#             $pres.Close()
#             $ppt.Quit() 
#         }
#     }
# }
# $dir = Get-ChildItem 
# titleRename $dir

# -Recurseで取得するようにしたらうまくいった
$dir = Get-ChildItem -Recurse
$ppt = New-Object -ComObject PowerPoint.Application
foreach($file in $dir) {
    # 拡張子が.pptxのファイルを対象にする
    If (($file.Name.Length -gt 5) -And ($file.Name.Substring($file.Name.Length - 5, 5) -eq ".pptx")) {
        $pres = $ppt.Presentations.Open($file.FullName)
        # プロパティのタイトルをファイル名に変更
        $pres.BuiltInDocumentProperties("title") = $pres.Name.substring(0, $pres.Name.length - 5)
        $pres.Save()
        # PDFに出力する
        $pres.SaveAs($file.FullName.Substring(0, $file.FullName.Length - 5), 32)
        $pres.Close()
    }
}
$ppt.Quit() 

# 上で方法でもできたけどもうちょっと最適化
# フィルターをかけてForEach-Objectにしてみた
$ppt = New-Object -ComObject PowerPoint.Application
Get-ChildItem -Recurse -Filter *.pptx | ForEach-Object {
    $pres = $ppt.Presentations.Open($_.FullName)
    # プロパティのタイトルをファイル名に変更
    $pres.BuiltInDocumentProperties("title") = $pres.Name.substring(0, $pres.Name.length - 5)
    $pres.Save()
    # PDFに出力する 第二引数はファイルタイプ。PDFは32
    $pres.SaveAs($_.FullName.Substring(0, $_.FullName.Length - 5), 32)
    $pres.Close()
}
$ppt.Quit() 

【フレームワーク】フレームワーク入門

ここではプログラミングにおけるフレームワークについて解説していきます。

一般的なフレームワーク

フレームワークという言葉は、プログラミング用語ではなく、様々な業界で用いられている用語です。
フレームワークは日本語では枠組みという意味をもちますが、多くの場合は「思考の枠組み」として用いられます。

よく知られているフレームワークの例としてはPCDAサイクルがあります。
PDCAは、Plan, Do, Check, Actの頭文字をとったものです。
PDCAサイクルは業務改善でよく用いられているフレームワークです。
特定の業務について、今よりも効率を上げて業務の質を上げたいとします。
その時、何の情報もない状態で改善策を考えるよりも、事前に計画を立てて計画に従って作業を行い、どこに問題があるのかを振り返りながら改善を進める方が改善が上手く可能性が高いです。
業務改善を効率よく行うために、PDCAサイクルというフレームワークを使用します。

他にも、経営やマーケティングの分野でも多くのフレームワークがあります。
経営やマーケティングで使用されるフレームワークには、SWOT分析、3P分析、4C分析などがあります。
ゼロから戦略や対策を考えるよりも、フレームワークという枠組みにそって考えることで、有効な戦略や対策を立てやすくなります。

プログラミングとは直接の関係はありませんが、フレームワークという言葉の意味として理解しておきましょう。

プログラミングにおけるフレームワーク

プログラミングにおけるフレームワークも、枠組みという意味では先に説明したものと同じです。
プログラミングの場合は主に開発の効率化を目的としてフレームワークを使用します。
予め作成されている枠組みに当てはめて開発をすることで、少ないコード量で開発を行うことができ、結果として開発効率が上がります。

フレームワークのメリット

開発効率が上がる

フレームワークを使うことの最大のメリットは開発効率が上がることでしょう。
どのフレームワークも、ほとんどの場合、フレームワークを使わずに開発するよりも少ないコード量でプログラムを書くことが可能になります。
対象のフレームワークを初めて使う場合は、覚えることが多いため、短期的にみると開発効率は落ちるかもしれません。
しかし、慣れてくれば開発規模が大きくなるほど開発効率が上がります。

品質を統一しやすくなる

フレームワークを導入すると、命名規則やコードの書き方に縛りが出てきます。
これは自由度が下がるという点ではデメリットと捉えることもできますが、開発者の人数が増えてもコードの書き方にばらつきが出にくいという点においては、品質を統一できる点においてメリットになります。

フレームワークのデメリット

学習コストが増える

フレームワークを使う場合、元となるプログラミング言語の知識と、プラスでフレームワークの知識が必要になります。
一度知識を身につけてしまえば効率よく開発ができますが、初めて使うフレームワークの場合、そのフレームワークの特徴やルールを覚える必要があり、学習コストがかかります。

プログラミングの知識がつきにくい

個人的にはフレームワークを使用することのデメリットはこれが大きいかもしれません。
フレームワークは書き方を覚えてしまえば効率よく開発できるのがメリットですが、逆に言うとルールさえ覚えてしまえばフレームワークの仕組みやプログラミング言語の深い知識がなくても開発ができてしまいます。
初心者のうちからフレームワークを使った開発ばかりをしていると、フレームワークの仕組みやメリットを知らないままでプログラマーとしてのスキルが上がらない可能性があります。
フレームワークは非常に便利で強力なツールですが、同時に仕組みなども学習する習慣を身に付けると良いでしょう。

様々なフレームワーク

ここでは具体的なフレームワークをいくつか紹介します。

CSSフレームワーク

  • Bootstrap
    classの指定だけで簡単に見た目の整ったレイアウトを作ることができるフレームワークです。

JavaScript

  • iQuery
  • Vue.js

Javaフレームワーク

PHPフレームワーク

Rubyフレームワーク

他にも言語ごとに様々なフレームワークが存在します。

代表的なフレームワークの機能

ここでは特定のフレームワークに依存しない、多くのフレームワークでサポートされる機能をいくつか紹介します。

DI

Dependency Injectionの略です。
直訳すると依存性の注入という意味です。
オブジェクト指向をサポートしているプログラミング言語Java,PHPなど)のフレームワークで実装されていることの多い機能です。
多くのオブジェクト指向の言語では、クラスを元にnewというキーワードを使ってオブジェクト(インスタンス)を生成します。
しかし、ソースコード上に直接newを使ってオブジェクトを作成するコードを書くと、クラス間の依存関係が強くなり、プログラムの柔軟性は低下します。
そこで、プログラムの柔軟性を高めるため、ソースコード上に直接newを書かずに、設定ファイルやアノテーションを用いることで変数に自動的にオブジェクトを注入する機能がDIです。
DIの機能を使うことで、クラス間の依存関係を弱くし、プログラムの柔軟性を高めることができます。

AOP

Aspect Oriented Programmingの略。
直訳するかアスペクト指向プログラミングです。
辞書的に説明すれば、横断的な機能を抜き出してプログラムに適用する手法。
例えば、メソッド(関数)を呼び出す前と呼び出した後にログの出力をしたいとします。
これを普通に実現しようとした場合、メソッドの呼び出しの前後にログを出力する処理を入れ込む必要があります。
プログラムの規模が大きくなるとそれなりに大変な作業です。
このような処理は、オブジェクト指向を活用してどれだけ上手くまとめても解決できません。
ロギング(ログの出力)意外にも、エラーの処理、トランザクション処理も同じ問題があります。
これを解決してくれるのがAOPです。

バリデーション

バリデーションは妥当性チェックのことで、主に画面で入力された値のチェックなどで使用します。
多くのシステムでは、IDやパスワード、名前や数値など画面上から様々な値を入力します。
ユーザーはどんな値を入力するかわからないので、入力値をチェックする必要があります。
例えば、
・ネールアドレスの入力欄なのにメールアドレスの形式になっていない
・電話番号の入力で桁数が合わない
・数値の入力欄に文字が入力されている
・入って欲しくない記号の文字が入っている
など、入力時に不正な値が入る可能性はたくさんあります。
これらをチェックする処理を手動で書こうとすると、入力値を受け取った後、多くの条件分岐を書かなくてはいけません。
そのような入力チェック処理を書かずとも、簡単な設定だけで入力チェックを行ってくれるのがバリデーションです。
Webアプリケーション用のフレームワークで実装されていることが多いです。

マッピング

マッピングとは紐付けの意味です。
例えばWebアプリケーションに特化したフレームワークの場合、URLマッピングという機能を持ったフレームワークが多いです。
URLマッピングとは、「このURLでアクセスされた時にこのメソッドが呼ばれる」という紐付けをする機能です。
フレームワークによってマッピングの方法は変わりますが、アノテーションを使ってマッピングしたり、メソッドの命名規則マッピングしたりします。

他にもO/Rマッピングなどがあります。
O/RマッピングはObject RDB マッピングです。
現在多くのシステムではデータを管理するのにRDB(リレーショナルデータベース)を使用します。
RDBでは表形式でデータを管理し、レコードという単位でデータを保存します。
一方、オブジェクト指向型のプログラミング言語ではオブジェクトという単位でデータを扱います。
このオブジェクトとRDBのデータの保持の仕方に差異があります。
インピーダンスミスマッチ)
この差異をうまく紐づけして、オブジェクト⇒RDBRDB⇒オブジェクト間を自動でデータのセット、取得をしてくれるのがO/Rマッピングです。

また、画面に入力されたデータを自動でオブジェクトにセットする仕組みが用意されたフレームワークもあります。

画面・オブジェクト間、RDB・オブジェクト間など、異なる要素の値の取得やセットを手動で行わなくても裏で自動的に実行してくれる仕組みがマッピングの機能です。

ソースコードの自動生成

フレームワークによっては設定からソースコードを自動的に生成してくれるような仕組みもあります。
例えば、プログラムからDBを操作する際にテーブルごとにDAOやEntityと呼ばれるクラスを作成することがあります。
これらのファイルを手動で作成するのは手間がかかりますが、フレームワークによってはコマンド一つでテーブルの構造から自動的にクラスを作成したりします。
逆にEntityの構造からテーブルを自動で作成できるものもあります。

デザインパターンとかリフレクションとか

システム開発フレームワークを利用する利点の1つは、中でどういう仕組みが働いているのかを知らなくても、ある程度書き方さえ覚えてしまえばプログラムが書けてしまう事にあります。
しかし、書き方を知っていても、中で何が起きているのかを知らないと、エラーが発生したときに対処することが難しくなります。
何より、既存のフレームワークを拡張して新しいフレームワークを作成といった応用ができません。
フレームワークがどのように作られていて、中で何が起きているかを知ることで、応用力が身に付くと言えます。

オブジェクト指向言語ではデザインパターンと呼ばれる設計に対する概念があります。
フレームワークを使って開発をしているとデザインパターンを意識する場面は少ないですが、フレームワーク自体の中身では様々なデザインパターンが使われていることが多いです。
デザインパターンを学習しても実際にそのようなクラス設計を現場で使う機会は少ないかもしれません。
しかし、デザインパターンを学習することで、フレームワークの中身でどのようなクラス構造になっているかがイメージしやすくなり、フレームワークの理解を助けます。

もう一つ、フレームワークを知るうえで欠かせない機能としてリフレクションがあります。
リフレクションとは、辞書的に説明すればプログラムでプログラムを動的に操作する機能のこと。
具体的には、文字列で受け取った値でインスタンスを作成したりメソッドを呼び出したりできる機能です。
例えば、Javaの場合だとインスタンスを作成する場合、

new A();

のようにクラス名を直接書き込む必要がありますが、 リフレクションを使うと

Class.newInstance("A");

のように書くことができます。
リフレクションの書き方の場合は文字列で受け取っているので、メソッドの引数などにすることで、動的に作成するインスタンスを変更できるようになります。
リフレクションを使うとこのように、ソースコードにハードコーディングしなくてもインスタンスの作成やメソッドの呼び出しが可能になります。
コードをあまり書かなくてもいい感じに動いてくれるフレームワークの内部ではこのような仕組みが働いているのです。

フレームワークがどのような技術で作られているのかを知ることで、内部の動きをイメージしやすくなり、エラーやトラブルが起きた時にも対処がしやすくなります。

何を学習すべきか

フレームワークプログラミング言語ごとにたくさんの種類があります。
また、どのフレームワークを使用するかはプロジェクトごとによって異なります。
そして流行のフレームワークは時代によって変わってきます。
そのため、明確にこれを習得すべきと言えるフレームワークはありません。

しかし、先に説明したようにどのフレームワークでも提供されている機能はある程度共通しています。
そのため、何か1つのフレームワークを身に付けることで、2つ目以降のフレームワークの習得は容易になってきます。

【Git】Gitの理解度チェック

Gitに関する理解度を確認するための問題集です。
解説はここには書きませんが、下記の記事を参考にください。

case10.hateblo.jp

case10.hateblo.jp

case10.hateblo.jp

用語

以下の用語の意味を簡潔に説明しなさい。

その他

  • バージョン管理システムを使用する目的を答えなさい
  • バージョン管理には集中管理型と分散管理型があるが、その違いを答えなさい
  • 集中管理型と分散管理型を比較した時に分散管理型のメリットは何か答えなさい
  • ブランチを使用することのメリットを答えなさい
  • コンフリクト(競合)が発生した場合の解決策を答えなさい
  • 作業ディレクトリにあるファイルでバージョン管理を行いたくないファイルがある場合どのようにして対処すればよいか答えなさい
  • プログラム開発に関するファイルをバージョン管理する場合、どのようなファイルを管理対象外にした方がよいか答えなさい

コマンド

コマンドラインで以下の操作を行うコマンドを答えなさい。
オプションがある場合はどんなオプションがあるかも答えなさい。

  • 設定の確認
  • リポジトリの初期化
  • クローン
  • 現在の状態の確認
  • ログの確認
  • ステージングエリアへの追加
  • コミット
  • リモートリポジトリの設定
  • プッシュ
  • プル
  • ブランチの変更

【JavaScript】石取りゲーム

JavaScriptを使って超簡単な石取りゲームを作成。
プレイヤーがAとBで交互に交換していき、1度に1~3個の石を取ることができる。
最後の1個を取った人が負け。
JavaScriptの勉強の参考に。

ソースコード

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>石取りゲーム</title>
    <style>
        body {
            text-align: center;
        }
    </style>
</head>
<body>
    <h1>石取りゲーム</h1>
    <p style="color:red" id="winner"></p>
    <p>残り:<span id="total"></span></p>
    <p>※1度に3つまで取得できます</p>
    <p id="stone">
        
    </p>
    プレイヤー<span id="player">A</span>さん
    <form>
        <p>石を<input type="number" id="num" name="num" min="1" max="3">個取る</p>
        <button type="button" id="btn" name="btn">決定</button>
    </form>
    <p id="message"></p>
    <script>
        'use strict';

        const disp = function(num) {
            let stone = '';
            for(let i=1; i <= num; i++) {
                stone += '●';
                if(i % 10 == 0) {
                    stone += '<br>';
                }
            }
            document.getElementById('stone').innerHTML = stone;
            document.getElementById('total').textContent = (num);
        }

        const firstStoneNum = 25;
        disp(firstStoneNum);

        // ボタンが押されたときのイベント処理
        document.getElementById('btn').addEventListener('click', function() {
            const total = Number(document.getElementById('total').textContent);
            const num = Number(document.getElementById('num').value);
            let player = document.getElementById('player').textContent;
            if(player === 'A') {
                player = 'B';
            } else {
                player = 'A';
            }

            if(total - num > 0) {
                disp(total - num);
                document.getElementById('player').textContent = player;
            } else {
                document.getElementById('stone').textContent = '';
                document.getElementById('total').textContent = '0';
                document.getElementById('winner').textContent = player + 'さんの勝利!'
            }
        });

    </script>
</body>
</html>

参考図書

【Linux】Linux入門(環境構築編)

ここではLinuxの環境を動かしながら学べるように、環境構築の方法を簡単に解説。

学習用でLinuxOSを動かすには、仮想環境を作るのが便利です。

VirtualBoxインストール

仮想化ソフト Oracle VirtualBoxをダウンロードしてインストールします。
ご自身のOSの環境に合わせてダウンロードしてください。
https://www.virtualbox.org/wiki/Downloads

VMWareの製品でも可能ですが、ここではVirtualBoxを使用します。

Linuxダウンロード

次にLinuxのダウンロードです。
仮想環境を作成するにはisoファイルと呼ばれるOSのイメージファイルが必要です。
ここではLinuxディストリビューションの中でも広く使用されているCentOSを使います。
下記のサイトからisoファイルをダウンロードします。
https://www.centos.org/download/

バージョンやCPUの規格のタイプなどを選ぶ必要があります。
よく分からなければとりあえず最新バージョンのx86_64を選択。
mirrorサイトが色々出てきますが、とりあえずどのサイトでも大丈夫。
ダウンロードできるファイルが色々あると思いますが、minimalのisoファイルをダウンロード。
CentOS-8.2.2004-x86_64-minimal.iso」こんな感じのやつ。
バージョン番号はダウンロードするタイミングによって変わっている可能性あり。

仮想マシン作成

  1. VirtualBoxを起動
  2. メニューから「新規」ボタン押下
  3. ダイアログが表示されるので必要項目を入力して「次へ」を押下
    名前:任意(CentOSとかにするとタイプとバージョンが勝手に入力される)
    マシンフォルダー:任意(デフォルトで大丈夫)
    タイプ:Linux
    バージョン:Red Hat(64 bit)
  4. メモリサイズ、ハードディスクを選択して仮想マシンを作成
    サイズなどは環境に合わせて適当に。
    基本デフォルトで問題ないかと。
  5. VitrualBoxの管理画面に仮想マシンが出来上がる
  6. できた仮想マシンを選択して「設定」を押下
  7. ストレージを選択
  8. コントローラ:IDEの中のディスク(空)を選択
  9. 光学ドライブ」にダウンロードしたisoファイルを指定する
  10. 「OK」を押下して設定を閉じる

Linuxインストール

  1. VirtualBoxの管理画面で作成された仮想マシンを選択して「起動」ボタン押下
  2. 別ウィンドウでLinuxの画面が開く
  3. 指示に従ってインストールを進める
    言語の設定、ディスクの設定、ユーザーの設定などがある。
    日本語を選択してディスク選択して、ユーザーの設定を行えばあとは勝手にインストールされる。
    ユーザーの設定はrootユーザーのパスワードを設定し、必要であれば一般ユーザーも作成してパスワードを設定しておく。
  4. インストールが終わった後に再起動することでLinuxが起動する
    ※この時、isoファイルを光化学ドライブに設定したままにしておくと、再度インストール画面が開いてしまうので注意。
    再起動前に設定画面から外しておく。
  5. 起動したら、インストール時に設定したユーザー名とパスワードを入力することで操作可能となる
    一般ユーザーを作成していない場合はrootユーザーでログイン。
    一般ユーザーも作成していた場合はそのユーザーでもログインできる。 通常はセキュリティなどを考慮して一般ユーザーを使う場合が多いが、権限の問題で操作が限定されたりもするので、勉強用であれば最初の方rootでログインしておいた方が無難。

外部から接続するための設定

インストールが完了すればVirtualBoxの画面からLinuxを操作することが可能です。
しかし、仮想マシンを操作している間はホストOS(VirtualBoxをインストールしているWindowsMacなど)を操作することができません。
毎回ホストOSと仮想マシンの操作を切り替えるのは面倒ですし、ホストOS側でコピーした内容を仮想マシン上で貼り付けることもできません。
そのため、ホストOS側からssh接続をしてホストOS側で操作したほうが便利です。
そのための設定をしていきます。

CentOSのネットワークの有効化

Linuxをインストールした段階ではまだネットワークはつながらない状態になっているはずです。
ネットワーク接続ができるようにするには有効化する必要があります。

以下のファイルを開きます。
vi /etc/sysconfig/network-scripts/ifcfg-enp03
などとすると開きます。
開いた後はiを押すと中身が修正できるようになります。
そして最後の行あたりにある
ONBOOT=no

ONBOOT = yes
に変更して保存します。
保存は「:wq」とすると保存できます。

ファイルを変更した後はネットワークを再起動します。
ネットワークを再起動するには
systemctl restart NetworkManager
を入力して実行します。

VirtualBox側の設定

VirtualBoxでも一つ設定を追加します。
仮想マシンの設定を開き、ネットワークを選択します。
アダプター1(割り当て:NAT)を選択し、「高度」を開き、ポートフォワーディングの設定を開きます。
名前:sshプロトコルTCP、ホストポート:2222、ゲストポート:22、IPは空白
でルールを追加します。

ホストOS型の設定

Mac OSの場合、デフォルトでsshコマンドが使用できるので、設定は不要です。
ターミナルを起動し、ssh root@localhost -p 2222
と入力し、rootユーザーのパスワードを入力するとログインができます。

Windowsの場合はssh機能を有効にする必要があります。
Windowsの設定から「オプション機能の管理」を開いて、「OpenSSH クライアント」の機能を有効にします。
有効にするとsshコマンドが使えるので、コマンドプロンプト、またはPowerShellを起動して
ssh root@localhost -p 2222
と入力してrootユーザーのパスワードを入力するとログインができます。

ログインが成功すれば、ホストOS側からのコマンドでLinuxを操作することが可能になります。

コマンド入力時の2222はポートフォワーディングで設定したポート番号です。
2222である必要はありません。
適当に使われていないであろうポート番号を適当にしてください。
rootは接続する際のユーザー名です。
Linuxに作成した一般ユーザーなどを使う場合はrootのユーザー名を変更してください。

用語解説

  • ssh
    通信を暗号化して遠隔ログインができる通信プロトコル
    UNIX系のOS(Mac OSLinux)では標準でsshコマンドがあり、それを使うことで遠隔ログインができる。
    Windowsの場合、Tera TermやPuTTYと呼ばれる遠隔ログインのフリーのソフトがあるが、Windows標準でも機能の拡張からsshコマンドが使えるようになった。

  • ポート番号
    通信プロトコルを特定するための番号。
    0~65535までの数値を使用することができるが、0~1023まではウェルノウンポートと呼ばれ、予約されている。
    sshは22番。

  • NAT
    Network Address Translation
    プライベートIPアドレスグローバルIPアドレスを変換する機能のこと。
    仮想化ソフトでは、ネットワークの設定でNATを利用すると、ホストOSのIPアドレスを共有して使用することができる。

  • ポートフォワーディング
    仮想化ソフトでNATの機能を利用すると、ホストOSと仮想マシンIPアドレスが同じになる。
    その場合、仮想マシンssh接続しようとしても、何もしなければホストOSのポート番号22に接続しようとしてしまう。
    そこで、ポート番号で2222を指定した場合は、仮想マシン側のポート番号22に接続されるように設定したい。
    ポートフォワーディングはこのようにホストOSへの特定のリクエストを仮想マシン側に転送するための機能。