AI can fly !!

AI がやりたい Web エンジニアのアウトプット (AI の知識は無い)

【Angular】angular-gridster2 の使い方をまとめてみた (日本初かもしれない)

Angular

はじめに

Angular で Windows 10 のスタートメニューにあるような Drag and Drop ができるタイルを実装するにあたり、何か良さげなパッケージが無いか探していたところ、 angular-gridster2 というパッケージを教えてもらったので、その使い方を調べてみました。

github.com

angular-gridster2 は Drag and Drop で移動可能なタイル群を Grid Layout で配置でき、タイルの追加・削除・リサイズも簡単に実装することができる素敵パッケージです。

また、オプションやイベントが複数用意されているため、行数・列数の上限やタイル周囲の margin などの細かい指定のほか、ユーザの操作に応じたコールバック関数の実行も可能です。

ライセンスは MIT License なので、著作権表示および本許諾表示といったルールさえ順守すれば商用利用も問題ありません。

そんな魅力あふれるパッケージではありますが、色々調べる中で直面した大きな問題が…

それは、日本語で書かれたドキュメントが皆無だということ!!

使い方は難しくないですが、 GitHub の公式リポジトリ公式 Demo サイト を参考にしつつ、実際にコードを書いて動かしながら記事にまとめるのはなかなか大変でした。。

tiberiuzuld.github.io

もしかしたら、この記事が angular-gridster2 を日本語で取り上げた最初のエントリーかもしれません!?

動作環境

OS Version
Ubuntu 20.04 LTS

Windows 10 Pro の Windows Subsystem for Linux (WSL 2) を使用

Environment Version
Node.js 14.17.0
npm 6.14.13
Package Version
@angular/cli 12.1.2
angular-gridster2 12.1.0

前提条件

  • Angular CLI がインストールされている
  • Angular CLI を使用した Angular アプリケーションが作成されている

angular-gridster2 概論

導入

インストール

npm install angular-gridster2 --save

インストールは npm でサクッと行います。

--save オプションって、いつの間にか指定しなくてもデフォルトで ON になっていたらしい…

知らなかった… (npm 5.0.0 以降だそうです)

使い方

NgModule (app.module.ts)

...
import { GridsterModule } from 'angular-gridster2';

@NgModule({
  ...
  imports: [
    ...
    GridsterModule,
  ],
})
export class AppModule {}

Angular のコンポーネントで使用するために、まずは NgModule で GridsterModule クラスをインポートします。

HTML (app.component.html)

<button type="button" (click)="addItem()">タイル追加</button>

<gridster [options]="options">
  <gridster-item [item]="item" *ngFor="let item of items; let index = index">
    <div class="draggable-handler">
      Header
    </div>
    <div>
      Content
    </div>
    <div>
      <button type="button" (click)="removeItem(index)">削除</button>
    <div>
  </gridster-item>
</gridster>
Element Property: Type Description
gridster option: GridsterConfig 各種設定やコールバック関数を指定
gridster-item item: GridsterItem タイルの位置やサイズを指定

gridster タグを配置し、 option プロパティへ GridsterConfig 型のデータをバインドします。

gridster の Style には width: 100%;height: 100%; が指定されているので、配置先の親要素と同サイズまで広がります。

gridster タグ内部の gridster-item タグが一つのタイルに相当し、 item プロパティへ GridsterItem 型のデータをバインドすることでタイルの位置やサイズを設定します。

Component (app.component.ts)

...
import { GridsterConfig, GridsterItem } from 'angular-gridster2';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  options: GridsterConfig = {};
  items: Array<GridsterItem> = [];

  ngOnInit(): void {
    this.options = {
      draggable: {
        enabled: true,
        ignoreContent: true,
        dragHandleClass: 'draggable-handler',
      },
      resizable: {
        enabled: true,
      },
      swap: true,
    };

    this.items = [
      { x: 0, y: 0, rows: 1, cols: 1 },
      { x: 0, y: 1, rows: 1, cols: 1 },
    ];
  }

  /** タイル追加 */
  addItem(): void {
    this.items.push({ x: 1, y: 0, rows: 1, cols: 1 });
  }

  /** タイル削除 */
  removeItem(index: number): void {
    this.items.splice(index, 1);
  }
}

gridster コンポーネントoption プロパティにバインドする GridsterConfig データと、 gridster-item コンポーネントitem プロパティにバインドする GridsterItem データを定義します。

また、タイル (gridster-item コンポーネント) の追加や削除も、このサンプルコードのように動的に行うことができます。

今回はサンプルのため固定位置にタイルを追加していますが、追加するタイルの位置とサイズには、本来配置したい任意の位置とサイズを指定してください。

リファレンス

主要そうなプロパティをリファレンスとしてまとめました。

各項目の説明は僕の独断と偏見に満ちた超訳になりますので、正確な内容は GitHub の公式リポジトリ公式 Demo サイト などの一次ソースをご確認ください。

また、こちらで紹介するプロパティは一部だけなので、さらに多くのプロパティを知りたい場合は、同じく公式 (ry

そして、今回は時間の都合上、イベントとコールバック関数については取り上げていないので、こちらについても (ry

GridsterConfig

Property Description Type Default
gridType Grid 内部の幅と高さの設定方法。 'fit' はスクロールバーが表示されないように Grid 内部の幅と高さの中で調整される。 String 'fit'
compactType Grid 内の Item の自動整列方法 (上寄せや左寄せなど) 。 'none' は自動整列無し。 String 'none'
displayGrid Grid 内の境界線の表示方法。 'onDrag&Resize' はドラッグ中やリサイズ中のみ、境界線を表示する。 String 'onDrag&Resize'
margin Grid 外枠と内部の Item の余白。 Grid の padding と同義。 Number 10
outerMargin Grid 外枠の内部の Item の余白有無。 Boolean true
outerMarginTop Grid 外枠と内部の Item の上部余白。 margin の値より優先される。 Grid の padding-top と同義。 Number null
outerMarginRight Grid 外枠と内部の Item の右部余白。 margin の値より優先される。 Grid の padding-right と同義。 Number null
outerMarginBottom Grid 外枠と内部の Item の下部余白。 margin の値より優先される。 Grid の padding-bottom と同義。 Number null
outerMarginLeft Grid 外枠と内部の Item の左部余白。 margin の値より優先される。 Grid の padding-left と同義。 Number null
fixedColWidth gridTypefixed を指定した場合に適用される、一列あたりの固定幅。 Number 250
fixedRowHeight gridTypefixed を指定した場合に適用される、一行あたりの固定高さ。 Number 250
minCols Grid の最小列数。 Number 1
maxCols Grid の最大列数。 Number 100
minRows Grid の最小行数。 Number 1
maxRows Grid の最大行数。 Number 100
defaultItemCols Grid 内の Item の横方向の規定サイズ。最小値は 1 。 Item の cols が省略された場合に使用される。 Number 1
defaultItemRows Grid 内の Item の縦方向の規定サイズ。最小値は 1 。 Item の rows が省略された場合に使用される。 Number 1
swap Grid 内の Item を移動する際、移動先に別の Item が存在した場合の制御。 true を指定すると、移動先の Item と位置の入れ替えを行う。 Boolean true
pushItems Grid 内の Item を移動・リサイズする際、移動・リサイズ先に別の Item が存在した場合の制御。 true を指定すると、移動先の Item を移動させる。 Boolean false
disablePushOnDrag Grid 内の Item を移動する際、移動先に別の Item が存在した場合の制御。 true を指定すると、移動先の Item を移動しない。 pushItems より優先される。 Boolean false
disablePushOnResize Grid 内の Item をリサイズする際、リサイズ先に別の Item が存在した場合の制御。 true を指定すると、リサイズ先の Item を移動しない。 pushItems より優先される。 Boolean false
pushResizeItems Grid 内の Item をリサイズする際、リサイズ先に別の Item が存在した場合の制御。 true を指定すると、リサイズ先の Item のサイズを縮小する。 pushItems と併用した場合、先に移動先の Item が可能な限り縮小された後に移動させる。 Boolean false
draggable Grid 内の Item のドラッグ制御方法。 Draggable -
resizable Grid 内の Item のリサイズ制御方法。 Resizable -

GridsterConfig.Draggable

Property Description Type Default
enabled Grid 内の Item のドラッグ可否。 true を指定すると Item がドラッグ可能になる。 Boolean false
ignoreContent Grid 内の Item 全域のドラッグ可否。 true を指定すると、 dragHandleClass で指定したクラスを持つ要素以外のドラッグが不可になる。 Boolean false
dragHandleClass ignoreContenttrue にした場合、ここで指定したクラスを持つ要素のみがドラッグ可能要素となる。ドラッグの可否は enabled の値に準ずる。 String ‘drag-handler’

GridsterConfig.Resizable

Property Description Type Default
enabled Grid 内の Item のリサイズ可否。 true を指定すると Item がリサイズ可能になる。 Boolean false

GridsterItem

Property Description Type Default
x Item の横方向の表示開始位置。 0 始まり。省略時、または既に Item が存在する場合は、自動的に空き位置に配置される。 Number undefined
y Item の縦方向の表示開始位置。 0 始まり。省略時、または既に Item が存在する場合は、自動的に空き位置に配置される。 Number undefined
cols Item の横方向のサイズ。最小値は 1 。省略時は GridsterConfig.defaultItemCols の値が使用される。 Number undefined
rows Item の縦方向のサイズ。最小値は 1 。省略時は GridsterConfig.defaultItemRows の値が使用される。 Number undefined
dragEnabled Item のドラッグ可否。 GridsterConfig.Draggable.enabled を Item 毎に上書きしたい場合に使用する。 Boolean undefined
resizeEnabled Item のリサイズ可否。 GridsterConfig.Resizable.enabled を Item 毎に上書きしたい場合に使用する。 Boolean undefined

おわりに

今まで OSS や商用ソフトウェアを含む様々なパッケージやライブラリを使用してきましたが、日本語の公式ドキュメントや多くの日本語ブログなどに、知らず知らずのうちに助けられてきたのだなと改めて痛感させられました。

自分の力だけでやってきたと思い込んできたものも、先人たちの偉大な教えや知恵の上で回っていたに過ぎなかったのです…

そして、これもまた過去何度も思ったことではありますが、やっぱり英語ができるエンジニアは有利だなと思いました。

日本語のドキュメントが無いだけで一気に作業効率がガタ落ちしますし、大体どこの (公式を含む) ドキュメントを見ても一次ソースは英語であることがほとんどです。

やっぱり、少しずつ英語の勉強もしないといかんな… _(-ω-`_)⌒)_

【Cloud】大手クラウドサービスの IaaS 運用コストを比較してみた

Cloud

はじめに

有名どころのクラウドサービスの IaaS の運用コストを調べる機会があったので、費用面から見た各社の特徴をまとめてみました。

ちなみに、僕は開発でクラウドサービスを利用したことはあるものの、導入や構築などの経験は一切ありませんので、完全なる素人が調べた内容になっています。

間違っているところがあれば、コメントで指摘頂けると助かります (´ε`; )

良い意味で浅い内容に仕上がっていると思うので、これからクラウドサービスを利用したいと考えている方には丁度良い取っ掛かりになるかもしれません。

また、タイトルには "運用コストを比較" と書いていますが、利用する規模や頻度等によって金額が大きく異なるため、具体的な金額等は一切書いていません。

一通り各社の料金形態について把握したら、それぞれの公式サイトにある料金計算ツールを使用して金額を見積もってみましょう。 (丸投げ)

比較対象

今回の比較対象となる各社の IaaS はこちら。

すべて 2021 年 6 月現在のデータでの比較となります。

え?それ IaaS なの?というつっこみは受け付けません。

クラウドサービスの運用コスト

Amazon Web Service (AWS) - Amazon Elastic Compute Cloud (Amazon EC2)

AWS の料金については、こちらに詳しく記載されています。

aws.amazon.com

以降は上記の公式ページからの引用と、僕の超訳まとめになります。

従量制料金

aws.amazon.com

Amazon EC2 は使用した分だけ課金される従量制料金となっています。

必要に応じてスケールすることが容易なため柔軟で無駄の無い運用を行うことができますが、例えば Amazon EC2 を利用して定額制のサービスを展開する場合、使用時間やトラフィックを見誤った料金設定を行うと赤字になる可能性があるため注意が必要です。

Amazon EC2 の主な支払いのプランは以下の通りです。

オンデマンド

aws.amazon.com

契約期間の縛りなどは無く、使用するインスタンス (Amazon EC2 上で稼働する仮想サーバ) の稼働時間に応じた料金を後払いします。

必要な規模の仮想サーバを必要なときに調達でき、料金も使用した分を後払いするため、無駄なコストや手間を省くことが可能です。

ただし、特に割引等は無いため、予め一定期間以上使用することが決まっていたり、必要なキャパシティが一定などの場合は、後述する割引有のプランがお勧めです。

スポットインスタンス

aws.amazon.com

ざっくり言うと、 AWS 上の余った Amazon EC2 領域を格安で利用できるプランです。

Amazon EC2 の余り領域が無くなればインスタンスは中断されてしまうことになるので、停止しても問題が無い用途のインスタンスに限るか、その他のプランのインスタンスと組合せて使用することになります。

利用料金は需給状況によってリアルタイムに変化しますが、割引率は大きく設定されており、上手く運用できればオンデマンドの最大 90% OFF で Amazon EC2 を使用することができるため、運用コストの大幅な削減に繋がります。

リザーブインスタンス (RI)

aws.amazon.com

予め指定したインスタンスを 1 年または 3 年といった期間で契約し、そのインスタンスを使用する場合に限り、オンデマンドの料金から最大 75% OFF で利用することができます。

また、オンデマンドやスポットインスタンスと違い、料金を前払いすることで更に割引率を高めることも可能です。

デメリットとしては、契約期間中は使用しなくても料金が発生することになるため、必ず一定のコストがかかることになります。

一定のスペックで定常的な仮想サーバの稼働が見込まれる場合はオンデマンドと比較してメリットがありますが、稼働状況に波がある場合は結果的にオンデマンドよりも高額になってしまう可能性があります。

Savings Plans

aws.amazon.com

リザーブインスタンスが特定のインスタンスを一定期間使用するという契約なのに対し、 Savings Plans はインスタンス全体の一定期間の特定の使用量を契約するようなイメージです。

ちょっと分かりづらいですが、 1 年または 3 年の期間でどのくらい使用するかを前もって契約しておくことで、オンデマンドで使用した場合と比較して最大 72 % OFF の割引を受けることができます。

リザーブインスタンスと違い、インスタンスを指定する必要が無く、 Amazon EC2インスタンス全体に対して割引が適用されるため、柔軟性のあるプランになっています。

デメリットは…うーん、特に無いように感じます。。

Microsoft Azure - Azure Virtual Machines

Microsoft Azure の料金についてはこちら。

azure.microsoft.com

以降は AWS と同様、公式ページからの引用と僕の超訳まとめです。

従量制料金

azure.microsoft.com

Azure Virtual Machines も Amazon EC2 と同様に、従量課金制の料金形態となっています。

割引についても Amazon EC2 と概ね同様ですが、 Microsoft Azure には Windows Server や SQL Server といった Microsoft 製品を使用する場合に適用される割引があるなど、 Microsoft ならではの強みが存在します。

Azure ハイブリッド特典 (Azure Hybrid Benefit)

azure.microsoft.com

もし既に Windows Server や SQL Server などのライセンス、またはサブスクリプション契約を有している場合、それを Azure Virtual Machines へ適用することができます。

この特典を後述する Azure Reserved VM instances などと組み合わせれば、通常の従量料金と比較して最大 85% OFF のコスト削減が可能になります。

オンプレミスの Windows Server からの移行や余っているライセンスがある場合は、他のクラウドサービスと比べて資源を有効活用できるため、現在 Microsoft 製品を主に使用しているなら Microsoft Azure を選択するメリットは大きくなります。

これこそ Microsoft ならではと言えますね。

Azure Spot Virtual Machines

azure.microsoft.com

これは Amazon EC2 のスポットインスタンスとほぼ同様のプランになります。

Amazon EC2 の場合は停止の 2 分前に通知が来ますが、こちらは 30 秒前の通知なので若干猶予が少ないです。

詳細は割愛します。 (決して該当の公式ページが翻訳されていなかったからではない)

Azure Reserved VM Instances

azure.microsoft.com

こちらも Amazon EC2リザーブインスタンスとほぼ同様のプランですが、支払いは全額一括前払いか毎月の分割前払いになります。 (Amazon EC2 は前払い無しも選択できます)

また、 Amazon EC2 との違いの一つとして、契約時に決めていた利用期間やインスタンスの変更、途中解約による一部返金など、後からでも契約内容を変更することが可能という点が挙げられます。

Google Cloud - Compute Engine

Google Cloud の料金についてはこちら。

cloud.google.com

以降は AWSMicrosoft Azure 同様、公式ページからの引用と僕の超訳まとめになります。

従量制料金

cloud.google.com

Google Cloud の Compute Engine も、前述の 2 社と同様、従量課金制となっています。

後述する割引については Amazon EC2Microsoft Azure と比べて若干少なく感じますが、今回詳細まで調べてはいないものの、そもそもの通常料金が他社よりも安いとの情報がインターネット上で散見されました。

単純に同程度のインスタンスを使用したケースで比較すると Google Cloud の方が安いようなので、後述する割引を組み合わせれば、もしかしたら一番運用コストを安く抑えることができるのかもしれません。 (もちろん使用状況によると思います)

確定利用割引

cloud.google.com

これまで見てきた Amazon EC2リザーブインスタンスMicrosoft Azure の Azure Reserved VM Instances と同様に、 1 年または 3 年間の利用契約をすることで、最大 57% OFF の割引を受けることができます。

途中でインスタンスのスペックを変更しても割引が適用されるので、稼働状況に合わせて柔軟にスケールすることが可能です。

継続利用割引

cloud.google.com

他社を含めたこれまでの割引と違い、こちらはインスタンスの実行時間が一定の割合を超過した際に自動で適用されるものになります。

この割引を適用させるための設定等は不要のため、つまりはたくさん使えば勝手に安くなってくれる長期優良割引みたいなものです。

ただし、前述の確定利用割引との併用はできないという点には注意が必要です。

おわりに

2021 年 6 月現在、様々なクラウドサービスが展開されているなとは思っていましたが、各社の料金形態だけでも非常に複雑なルールやプランが存在するということが分かりました。

さらに、今回取り上げた 3 社はそれぞれ数十から数百のクラウドサービスを展開しており、ちょっと調べた程度ではその全貌を知ることは不可能に近いです…

この他に Oracle Cloud や Alibaba Cloud といった他社クラウドサービスもそれぞれ独自のプランや強みを持っていて、これらの中から最適なクラウドサービスを見付けるのは至難の業です。

ただ、逆に考えればこれらすべてとは言わないまでも、いくつかのクラウドサービスに精通した知識や経験を有することは他のエンジニアとの差別化にも繋がり、より自分自身の市場価値の向上に寄与するなとも思いました。

これまであまりクラウドサービスを使用する機会は多くありませんでしたが、時代に取り残されないように、今後はもっとプライベートでも積極的にクラウドサービスを使っていきたいと思います。

なんてことを 2021 年の今頃言っているようでは、もうずいぶん出遅れてしまっているんでしょうけれど ( っ・∀・)≡⊃ ゚∀゚)・∵.

【脱IE】Internet Explorer のサポート終了が与えるレガシーな社内 Web システムへの影響と対策

Internet Explorer

はじめに

先日、 Microsoft から Internet Explorer デスクトップアプリ (以下「IE」と称する) のサポート終了が発表され、一部の Windows OS のバージョンを除き、 2022 年 6 月 15 日 (水) をもって IE はその長い歴史に幕を閉じることになりました。

blogs.windows.com

IE のサポート終了の流れは既に数年前から始まっていて、主要な Windows OS においては 2016 年 1 月に IE11 以外のバージョンのサポートを終了しており、それから 5 年以上の年月を経て、ようやくの IE 終了に歓喜する Web エンジニアも少なくないと思います。

直近 5 年間の国内外の Web ブラウザシェアの推移を見ると、 IE の全体に占める割合は一桁台で減少の一途を辿っており、人によって見方は変わると思いますが、モダンブラウザへの移行は概ね順調であると言えます。

gs.statcounter.com

しかし、この話題でよく問題になるのは、 IE 独自の機能拡張 *1 に依存した処理が至る所に実装された、昔から存在する企業内の業務用社内 Web システムです。

Web エンジニアにはお馴染みですが、 IEMicrosoft によって独自の機能拡張が施されており、 Web 標準に準拠していない IE でしか使用できない機能が存在します。

これらが多用されたレガシーな Web システムをモダンブラウザに対応させるための工数は少なくなく、特に社内向け Web システムは利益に直結しないケースも多いことから、開発が先送りされてきたのが現状だと思います。

ということで今回は、レガシーな社内 Web システムでよく使用されている IE 独自の主だった機能拡張 *2 とその代替手段、そして IE からモダンブラウザへの移行時に合わせて検討した方がいいと思われることを独断と偏見でまとめてみました。

モダンブラウザでは使用できない IE 独自の機能

IE 独自の機能拡張については、 Windows Blog に Windows 10 の標準ブラウザである Microsoft Edge でサポートされない IE の機能や API がまとめられており、 Microsoft Edge でサポートされない ≒ Web 標準でない ≒ IE 独自の機能拡張 と理解しても、大きく間違ってはいないと思います。

blogs.windows.com

これらの中から私の経験を踏まえて、おそらく多くの現場で使われているであろう技術とその代替手段を取り上げていきます。 (完全に独断と偏見です)

ActiveX

ActiveXMicrosoft が開発したインターネット関連技術群の総称で、初っ端からですが、もしかしたらこれが一番厄介かもしれない機能です。

IEJavaScript エンジンである Chakra (jscript9.dll) では、細かいことをすっ飛ばすと、 ActiveXObject を使用することで Windows 上のファイル操作やコマンドが実行できるという、今となってはとんでもない機能が用意されています。

もちろん、これを使用するためには IE の設定でセキュリティレベルを下げるなどの明示的な対応が必要なため、一般的には安全だと思われるイントラネット内での社内 Web システムだからこその機能であると言えます。

よくある例

var fso = new ActiveXObject('Scripting.FileSystemObject');

fso.DeleteFile('ファイルパス', true); // 悪用厳禁

代替手段

ActiveXObject を使用すればある程度何でもできてしまうので社内向け Web システムでは意外と多く使用されてきたと思いますが、当然セキュリティはガバガバになるわけで、モダンブラウザにおいてはこんな操作ができるわけがなく、 Web 標準や ECMAScript にもこれに代わる機能は存在しません。

モダンブラウザでサポートされる WebAssembly でも、将来的にどうなるかは分かりませんが、現時点ではセキュリティ上の制約からローカルファイルへのアクセスは難しそうです。

基本的には設計を見直すか、何かしらのファイルをダウンロードしてローカル PC 上で手動で実行してもらうなどの方法を取らざるを得ないため、確実に仕様を変える必要が出てきます。

一番厄介と書いた理由は、これを決裁権を持つ偉い人に説明して納得してもらうのが難しい可能性があるからです…

これを説明しなければならない担当者の方には、大変ですねとしか言えません…

VBScript (Web クライアントスクリプト処理)

VBScript には、 IE で実行される Web クライアントスクリプト処理と Internet Information Service (IIS) で実行される Web サーバスクリプト処理 (Acrive Server Pages (ASP)) があり、今回対象となるのは IE で実行される Web クライアントスクリプト処理になります。

IIS で実行される Web サーバスクリプト処理はブラウザには依存しないため、 IE のサポート終了による影響を受けません。 (IIS 10.0 のサポート終了日は 2027 年となっているので、まだまだ VBScript 自体は健在のようです…)

Windows Blog で言及されていますが、既に IE11 では VBScript の実行が非推奨となっており、既定の設定では VBScript は実行されません。

blogs.windows.com

ただし、後述する Document mode による互換表示設定を行うことで VBScript の実行が可能になるため、 VBScript を使用している社内 Web システムでは、 IE の設定や HTML の meta 要素などで互換表示設定を行っているケースが多いと思います。

よくある例

<script language="VBScript">
MsgBox(
  "モダンブラウザへ移行してよろしいですか?", 
  vbOkCancel + vbQuestion, 
  "モダンブラウザ移行"
)
</script>

代替手段

VBScript に関しては、基本的には JavaScript への書き換えが可能です。

VBScript の組み込み関数のすべてが JavaScript の標準組み込みオブジェクトでカバーできるわけではありませんし、もちろん VBScript で書かれたコードを解析して JavaScript に書き換えるという手間は発生しますが、大きな問題にはならないはずです。

"基本的に" と書いたのは、 VBScript の組み込み関数で用意されている CreateObject 関数が問題で、これを使用すれば COM オブジェクト (ActiveX オブジェクト) への参照が取得でき、前述の ActiveX で書いたこととと同様のことができてしまいます。

Dim Fso

Set Fso = CreateObject("Scripting.FileSystemObject")

Fso.DeleteFile("ファイルパス") ' やっぱり消せちゃう

やはりこれに対しても前述した通り、設計を見直すなどの対応が必要となり、偉い人へ説明する担当者の方は (ry

Document modes (互換表示)

Web 標準は W3C (World Wide Web Consortium) 、 JavaScript の規格である ECMAScriptECMA International のもとでそれぞれ標準化が進められており、その時々のニーズに沿った新しい仕様・規格が活発に議論されています。

各モダンブラウザは基本的にこれらの標準化された仕様に準拠するよう実装され、新機能の先行実装や非推奨になった機能の削除など、比較的頻繁にアップデートが行われています。

IE もバージョンが上がる度に徐々に Web 標準への移行が進み、最終バージョンである IE11 では比較的モダンブラウザに近いレンダリングや動作をしますが、 IE8 やそれ以前のバージョンはかなり癖があると言っても過言ではありません。

こうした癖のある古い Web ページや Web システムを動作させるため、 MicrosoftIE後方互換性を維持するために実装した機能が Document modes です。

Document modes が使えなくなるということは、前述した二つ (ActiveXVBScript)) も含め、 IE の過去バージョンでのエミュレート (互換表示) ができなくなることを意味するため、モダンブラウザへ移行するためには Web 標準や ECMAScript に準拠したコードへの修正が必要になります。

よくある例

<!-- Document modes でエミュレートするバージョンを指定 -->
<meta http-equiv="X-UA-Compatible" content="IE=5">
<script>
  // attachEvent() は IE8 以前でしか動かない
  // showModalDialog() は多くのモダンブラウザで廃止済み
  document.getElementById('button')
    .attachEvent('onclick', function () {
      window.showModalDialog('modal.html');
    });
</script>
<frameset cols="30%, *">
  <frame src="side_menu.html" name="side_menu">
  <frame src="main.html"> name="main">
  <noframes>
    現在ご利用のブラウザは frameset に対応していません。
  </noframes>
</frameset>

代替手段

Web 標準の HTML / CSS を書こう!
そして、 ECMAScript に準拠した JavaScript を書こう!

これに尽きます。

とは言っても、先にも述べた通り社内 Web システムではなるべく工数を抑えたいという事情があるので、 JavaScript については attachEventshowModalDialog といったキーワードで検索して必要な箇所のみ修正を行い、レイアウト (HTML / CSS) については非常に面倒ではありますが、実際にモダンブラウザで表示させながら修正を加えていくしかないのかなと思います。

もちろん、 frameset などの分かりやすいものであれば、キーワードで検索して修正するのも一つの方法です。

特に古い quirks mode については Microsoft Docs で確認することができますが、これを一つ一つ検索して対応するのは至難の業です…

docs.microsoft.com

こうした対応をするにあたって、ここであえて社内 Web システムの良いところを挙げるならば、エンドユーザが社内の人であることが多いので、多少の不具合は何とかなるということでしょうか。

ただし、これもまた担当者の立場が外注や派遣だったりすると (ry

モダンブラウザ移行時に対応したいこと

ここからは、 IE からモダンブラウザへ移行する際、合わせて検討してもいいと思うことを挙げていきます。

ちなみに、どうせモダンブラウザへ移行するなら、 Angular や Vue.js で SPA 化したら?というのは無しの方向でお願いします。

あくまでも基本的な路線はなるべく工数をかけずに、でも、どうせやるなら一緒に対応できることは合わせてやってしまいたいという目線で考えてみました。

jQuery

IE を使用する社内 Web システムでは、 jQuery を使用しているケースが多いと思います。 (hrgm 調べ)

jQuery は 2021 年 6 月現在で 3.6.0 が最新バージョンとなっていますが、 IE で使用できる jQuery のバージョンは大きく二つに分類されます。

IE jQuery
~ 8 1.n
9 ~ 2.n, 3.n

IE8 と IE9 の間を境にして、 IE8 以前はバージョン 1.nIE9 以降はバージョン 2.n3.njQuery が使用可能で、 jQuery のバージョンが上がれば使用できるメソッドなどに若干の違いが出ますが、バージョンアップにより軽量化やパフォーマンス向上の恩恵が受けられます。

また、各モダンブラウザについては、基本的に最新版とその一つ前のバージョンへの対応が明記されています。

jquery.com

もしモダンブラウザへの移行を考えているのであれば、合わせて jQuery の最新化も検討してみてはいかがでしょうか。

ただし、 jQuery のバージョンアップには少ないながらもいくつか破壊的な変更が含まれており、元々非推奨だったメソッドの削除などが行われているため、移行には多少注意が必要です。

jQuery 公式から提供されている移行用ライブラリを使用するか、もしくは社内 Web システム内で使用している jQuery の機能には一定の傾向があると思うので、例えば load メソッドなど多用している場合はキーワード検索で修正箇所を特定するなど、ピンポイントの対応でもいいかもしれません。

github.com

Bootstrap

Bootstrap も比較的使用されていることが多いと思いますが、つい最近 Bootstrap 5 がリリースされ、このバージョンから jQuery が不要になるなどの大きな変化がありました。

Bootstrap も jQuery と同じく、せっかくモダンブラウザへ移行するならバージョンアップを検討してもいいと思いますし、もし将来的に IE だけでなく jQuery からの脱却も視野に入れているならば、このタイミングで Bootstrap 5 へ移行してしまうのもアリかと思います。

かなり端折った Bootstrap の各バージョンとブラウザへの対応状況は以下の通りですが、 Bootstrap はバージョンが変わるとデザインや書き方も多少変わるため、 jQuery と同じくコードの修正やターゲットブラウザでの確認が必要になります。

Bootstrap jQuery Browser
3 要 (※) IE8 ~, 各モダンブラウザ
4 要 (※) IE10 ~, 各モダンブラウザ
5 不要 IE 非対応, 各モダンブラウザ

※ Bootstrap で用意されている Components を使用しない場合、 jQuery は必須ではない。

Bootstrap 3 のサポートは既に終了していますが、 Bootstrap 4 以降は基本的に jQuery と同様に各モダンブラウザの最新版とその一つ前のバージョンがサポートされます。

Bootstrap のマイグレーションについては公式ドキュメントにも記載があるので、これを見ながら対応すれば大丈夫だと思います。 (簡単だとは言ってない)

getbootstrap.jp

getbootstrap.jp

その他のライブラリについて

jQuery や Bootstrap といった有名なライブラリだけでなく、中にはあまり知られていないライブラリを使用していることもあると思います。

これらは既に開発が止まってしまっているケースも多く、今まで述べてきたような IE に依存する実装が内部でなされている場合は、別のライブラリへ切り替えるか自前で実装を行わなければいけません。

運良く開発が続いていてモダンブラウザへの対応がされていたり、何もしなくてもそのままモダンブラウザで動けばラッキーくらいに考えておき、基本的には対応が必要になると思っていた方が無難かもしれません。

社内 Web システムでは外部のライブラリを使用するために許可が必要だったりするので、あまり無いことだとは思いますが、過去または現在の担当者が勝手にライブラリを入れていたりすると、なかなか面倒なことになったりします…

IE を使い続けることはできないか

Microsoft による IE のサポートは終了しますが、アプリ自体が使えなくなるわけではないはずなので、おそらく継続して IE を使用することはできると思います。

ただし、サポートが終了するということはセキュリティアップデートも当然行われないため、特に企業内での既定ブラウザとして IE を使い続けることはお勧めできません。

それではモダンブラウザへの移行に伴い、これまで使用してきた社内 Web システムを必ず改修しなければいけないかと聞かれたら、そういうわけでもありません。

Microsoft EdgeInternet Explorer モード

ここまで色々書きましたが、 IE の後継ブラウザである Microsoft Edge には IE モードが搭載されており、実はこの機能を使用すれば、これまで取り上げた ActiveX コントロールや Document mode などをそのまま使用することができます。

docs.microsoft.com

もちろん、この IE モードにもサポート期限は存在しますが、現時点においては少なくとも 2029 年までのサポートが明言されています。

docs.microsoft.com

これはつまり、 2022 年 6 月に IE のアプリとしてのサポートは終了するものの、使用する Web ブラウザを Microsoft Edge へ移行してしまえば、さらにあと 7 ~ 8 年は今まで同様にレガシーな Web システムが利用可能ということを意味します。

各企業の方針にもよるとは思いますが、基本的に機能追加などを改修をほとんど行わない場合は Microsoft Edge への移行のみを行い、 Web システム自体には手を加えずに IE モードのサポート期限ギリギリまで粘るということも不可能ではありません。

しかし、機能追加や改修を頻繁に行うような Web システムになると、対応を先送りすればするほど IE モードのサポート終了まで技術的な負債を積み上げることになるので、やはりどこかのタイミングで Web 標準への対応を行った方が、長い目で見れば工数が少なくて済むという見方もできます。

この辺りは社内 Web システムの開発頻度や使用状況、モダンブラウザ対応を行うにあたってかけられる工数や費用によって変わってくるので、担当部門や各ステークホルダーと要相談になるかと思います。

おわりに

現在のブラウザシェアでは一桁台となりましたが、 IE はこれまで長きに渡り Web ブラウザのデファクトスタンダードの地位を守ってきました。

それ故にバージョンアップやサポート終了による影響力は甚大で、ここまでずっと Microsoft によって後方互換性が維持されてきたのも頷けます。

IE のサポートが終了すると言っても、前述した通り Microsoft Edge では引続き IE モードによって既存の Web サイトや Web システムを使用することができるため、一番取り残されているであろう社内 Web システムの Web 標準への対応はまだ先になるかと思います。

ただ、アプリとしての IE が無くなり、社内の既定ブラウザが Microsoft Edge を含むモダンブラウザへ移行することには大きな意味があると考えます。

それは、もし今後新規で Web システムを構築する場合、何の気兼ねもなく最新の Web 関連技術を使用することができるからです。

今はまだ涙をこらえて秀丸でコードを書いて IE を手動でリロードしながら開発をしていても (数年前の僕です) 、 Visual Studio Code でコードを書いて CLI でタスクランナーを走らせながらブラウザをライブリロードするなんて未来がやってくるかもしれません! (適当)

でもこれ、偉い人が理解して許可してくれるかどうかは…おっと、長くなったので今日はここまで。

それでは、社内 Web システム開発に関わるすべての Web エンジニアに幸多からんことを (*˘人˘*)

*1:紛らわしいが、アドオン (拡張機能) ではない。

*2:しつこいようですが、アドオン (拡張機能) ではない。

【Python】pyenv で複数バージョンを管理する (チートシート付)【Ubuntu】

python-logo

はじめに

サードパーティ製のパッケージだけでなく、プログラミング言語自体も日々のアップデートによって頻繁にバージョンアップが行われており、継続的なアプリ開発を行っていく上では、アプリ毎に使用する言語やパッケージのバージョンを管理する必要が出てきます。

最近、 WSL 2 を使用して UbuntuPython の開発環境を構築した際に、複数の Python のバージョンを管理するために pyenv を導入したので、インストール方法と使い方についてまとめてみました。

おまけとして、主に使用する pyenv コマンドをチートシートとして合わせてまとめています。

動作環境

OS Version
Ubuntu 20.04 LTS

Windows 10 Pro の Windows Subsystem for Linux (WSL 2) を使用

Application Version
Git 2.25.1
pyenv 1.2.21

pyenv のインストール

pyenv のソースコードGitHub から clone して .bashrc へ必要な情報を追記するだけで、 pyenv のインストールは完了します。

詳細は GitHub の pyenv 公式の README.md に書いてあるので、こちらを見た方が間違いないです。

github.com

以下は pyenv 公式のインストール手順を参考に、実際に Ubuntu の環境へインストールした手順になります。

1. pyenv のソースコードを clone する

git clone https://github.com/pyenv/pyenv.git ~/.pyenv

ユーザのホームディレクトリ直下に、 GitHubリポジトリから pyenv のソースコードを clone します。

2. 環境変数を定義する

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc

環境変数 PYENV_ROOT へ先程 clone した .pyenv ディレクトリのパスを定義し、次に環境変数 PATH.pyenv/bin を追加する処理を、ユーザのホームディレクトリ直下にある .bashrc へ追記します。

3. pyenv 初期化処理を .bashrc へ追記する

echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.bashrc

pyenv init - では、 pyenv に必要な環境変数の定義や初期化処理が実行されます。

実際の処理の内容は、 echo "$(pyenv init -)" で確認できます。

4. Bash (シェル) を再起動する

exec "$SHELL"

.bashrc に必要な処理をすべて書いているので、 source ~/.bashrc でも大丈夫のような気がしますが、 pyenv 公式のインストール手順には上記スクリプトが書いてあるので、素直に Bash を再起動します。

正確には、新たなシェルを起動して自分自身と置き換える、でしょうか?

これで pyenv のインストールは完了です。

pyenv の使い方

pyenv コマンドを使用して、 Python のインストールや python コマンドで実行される Python のバージョンの設定を行います。

Python のインストール

# Python のバージョン 3.9.0 をインストール
pyenv install 3.9.0

インストールしたい Python のバージョンを指定して、 pyenv install コマンドを実行します。

pyenv でインストール可能な Python のバージョンは、 pyenv install --list で確認することができます。

【エラー発生時】Ubuntu に不足するパッケージを追加

pyenv で Python をインストールする際、パッケージが不足していると Python のビルドでエラーが発生するか、インストールに成功しても一部のモジュールが使用できない場合があります。

今回使用した環境は WSL 2 上のまっさらな Ubuntu 20.04 LTS ですが、 pyenv のみインストールして Python 3.9.0 をインストールしたところ、ビルドエラーが発生しました。

pyenv の Python のインストールログは、 /tmp/ ディレクトリに python-build.yyyymmddhh24miss.fff.log というファイル名で出力されます。

GitHubpyenv 公式 Wiki に OS 毎の推奨ビルド環境が記載されているので、こちらを参考に必要なパッケージを追加しましょう。

github.com

僕の環境 (Ubuntu 20.04 LTS) では、以下のパッケージを追加することで、正常に Python をインストールできるようになりました。

sudo apt update
sudo apt upgrade
sudo apt install build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev tk-dev libffi-dev liblzma-dev libgdbm-dev libdb-dev
Packages Description
build-essential gcc や make などのビルドパッケージ群
libssl-dev Python 標準モジュールの依存パッケージ
zlib1g-dev Python 標準モジュールの依存パッケージ
libbz2-dev Python 標準モジュールの依存パッケージ
libreadline-dev Python 標準モジュールの依存パッケージ
libsqlite3-dev Python 標準モジュールの依存パッケージ
tk-dev Python 標準モジュールの依存パッケージ
libffi-dev Python 標準モジュールの依存パッケージ
liblzma-dev Python 標準モジュールの依存パッケージ
libgdbm-dev Python 標準モジュールの依存パッケージ
libdb-dev Python 標準モジュールの依存パッケージ

Python のインストールは、正常に完了するまで何度でもリトライすることが可能です。

使用する Python のバージョン切替

# 現在のシェル固有の Python のバージョンを 3.9.0 に設定
pyenv shell 3.9.0

# カレントディレクトリ以下で固有の Python のバージョンを 3.9.0 に設定
pyenv local 3.9.0

# すべてのシェルで使用される Python のバージョンを 3.9.0 に設定
pyenv global 3.9.0

使用するコマンドにより、設定する Python のバージョンの有効範囲が変わります。

複数の設定が存在する場合の優先順位は shell > local > global となります。

現在設定されている Python のバージョンは、 pyenv version コマンドで確認できます。

Python のアンインストール

# Python のバージョン 3.9.0 をアンインストール
pyenv uninstall 3.9.0

不要になった Python のバージョンは、 pyenv uninstall コマンドでアンインストールできます。

venv との組み合わせ

pyenv は Python 自体のバージョンを管理するものですが、これと合わせて Python 標準ライブラリの venv を利用することで、設定した Python のバージョンでパッケージを管理する仮想環境を作成することができます。

# Python のバージョンを設定
pyenv shell 3.9.0

# カレントディレクトリに仮想環境を作成
python -m venv --upgrade-deps venv

# 仮想環境を有効化
source venv/bin/activate

この例では pyenv shell コマンドを使用して現在のシェル固有の Python のバージョンを設定していますが、次回からは pyenv での Python の設定内容にかかわらず、仮想環境を有効化するだけで仮想環境作成時に設定したバージョンの Python が使用できます。

pyenv コマンドチートシート

Command Description
pyenv install --list pyenv でインストール可能な Python のバージョンを一覧表示
pyenv install [version] 指定したバージョンの Python をインストール
pyenv versions pyenv でインストールした Python を一覧表示
pyenv shell [version] 現在のシェルで使用する Python のバージョンを設定
pyenv local [version] カレントディレクトリ以下で使用する Python のバージョンを設定
pyenv global [version] すべてのシェルで使用する Python のバージョンを設定
pyenv version 現在設定されている Python のバージョンを表示
pyenv uninstall [version] 指定したバージョンの Python をアンインストール

※ その他のコマンドや詳細は GitHub の pyenv 公式 Command Reference を参照

github.com

おわりに

pyenv を使用すれば一つの OS 上で複数の Python のバージョンを管理することができますが、アプリ開発環境という視点で見れば PythonPython パッケージのバージョンだけでなく、 Web サーバや DBMS などのミドルウェアのバージョンも管理する必要があります。

最近は WSL 2 によって Windows ユーザにも Docker が身近になりつつあるので、 今後は Web サーバや DBMS などのミドルウェアも合わせてコンテナ化し、一つのアプリ開発環境として管理するのが主流になるかもしれません。

とは言っても、手軽に Python のバージョン管理を行う際はやはり pyenv が有用なので、要件に合わせて使い分けするのがベターではないでしょうか。

ちなみに僕は今 Docker に興味津々なので、ある程度使えるようになったら、次は Docker のまとめエントリを書きたいと思っています (o´艸`)

【Oracle Cloud】Autonomous Transaction Processing への接続方法まとめ【Free Tier】

ORACLE CLOUD

はじめに

プライベートで使用している Oracle Database 19c から、 Oracle Cloud Infrastructure の Autonomous Database へデータベースの移行を行いました。

移行先は Autonomous Database のトランザクション処理に最適化された Autonomous Transaction Processing です。

Autonomous Transaction Processing をプロビジョニングしてデータベースを作成するまでは、 Web ブラウザから GUI ですべての操作を完了することができるので、特に難しいことはありません。

Oracle Data Pump を使用したデータ移行の方法は 別記事 を参照いただくとして、今回はクライアントから Autonomous Transaction Processing への接続方法についてまとめました。

ai-can-fly.hateblo.jp

ちなみに、 Oracle Cloud には Free Tier という常時無償のプランがあり、今回取り上げている Autonomous Transaction Processing の Always Free Autonomous Database では、一つのデータベースあたり 20GB まで Exadata ストレージを永久に無料で使用することができます。

動作環境

Cloud

Cloud
Oracle Cloud Infrastructure
Product
Oracle Autonomous Transaction Processing

Autonomous Transaction Processing とは

ハードウェアの構成や管理、ソフトウェアのインストールなどのデータベース管理を必要とせず、ワークロード要件に応じて自動スケーリングなどを行う Oracle Cloud 上に構築されたクラウド・データベース・サービスです。

OLTP (オンライントランザクション処理) およびリアルタイム分析アプリケーションのデータベース操作に最適化され、ミッションクリティカルなアプリケーションのリクエストを満たすために即座にスケーリングできる自動運転、自動保護、自己修復データベースサービスを提供します。

www.oracle.com

簡単に言えば、運用・保守などをほとんど考えずに使用できる、めちゃくちゃ使い勝手の良い Oracle Database です!

Client

OS Version
Windows 10 Pro 1909
Application Version
PowerShell 5.1.18362.752
SQL*Plus (Oracle Client) Release 19.0.0.0.0 - Production

前提条件

  • Oracle Cloud Infrastructure アカウントを作成済み
  • Oracle Autonomous Transaction Processing インスタンスをプロビジョニング済み
  • クライアント PC に Oracle Client をインストール済み

Autonomous Transaction Processing への接続

Autonomous Transaction Processingは Oracle Net Services をサポートしており、インターネットを介して複数の方法で接続することができます。

今回はクライアント資格証明 (ウォレット) を使用して、 Autonomous Transaction Processing へ Oracle Call Interface (OCI) 接続を行う方法を取り上げます。

接続準備

クライアント資格証明 (ウォレット) のダウンロード

まず、クライアント資格証明 (ウォレット) を Oracle Cloud Infrastructure コンソール から ダウンロードします。

ダウンロードの詳細は、 Autonomous Transaction Processing の公式ドキュメントをご覧ください。

docs.oracle.com

ダウンロードしたクライアント資格証明 (ウォレット) は Zip 形式に圧縮されていますが、 Oracle Call Interface 接続で使用する際は解凍する必要はないので、Zip 形式のまま任意のディレクトリに格納します。

格納場所に指定はありませんが、接続情報が記載されたファイルなのでセキュアなディレクトリに保管しましょう。

今回は例として、ユーザのホームディレクトリの直下へ専用のディレクトリを作成して格納します。

C:\Users\hrgm\OracleCloud\Wallet.zip

なお、クライアント資格証明 (ウォレット) は Zip 形式のまま使用しますが、後述する sqlnet.oratnsnames.ora の編集を行う際に圧縮ファイルの中のファイルを参照する必要があるため、どこでもいいので一時的なワーキングディレクトリに解凍もしておきます。

sqlnet.ora (プロファイル構成ファイル) の更新

解凍したクライアント資格証明 (ウォレット) の中にある sqlnet.oraテキストエディタで開き、その中の 1 行をクライアント PC にインストールされている Oracle Client の sqlnet.ora へ追記します。

[クライアント資格証明 (ウォレット)]/sqlnet.ora

WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY="?/network/admin")))
SSL_SERVER_DN_MATCH=yes

sqlnet.oraWALLET_LOCATION = ... の 1 行をコピーし、クライアント PC の sqlnet.ora の最終行にペーストします。

ペースト後、 DIRECTORY の値を Zip 形式のクライアント資格証明 (ウォレット) を格納したディレクトリパスとクライアント資格証明 (ウォレット) ファイル名に修正し、ファイルを上書き保存します。

[ORACLE_HOME]/network/admin/sqlnet.ora

...(元々の記述)

WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY="C:\\Users\\hrgm\\OracleCloud\\Wallet")))

Windows の場合、 DIRECTORY に指定するクライアント資格証明 (ウォレット) のファイル名に拡張子は付けません。 また、バックスラッシュはエスケープする必要があるので注意してください。

tnsnames.ora (TNS 構成ファイル) の更新

sqlnet.ora と同様に、解凍したクライアント資格証明 (ウォレット) の中にある tnsnames.oraテキストエディタで開き、クライアント PC の tnsnames.ora へ追記します。

[クライアント資格証明 (ウォレット)]/tnsnames.ora

(全文)

こちらは sqlnet.ora と違い編集は不要なので、クライアント PC の tnsnames.ora の最終行へそのまま全文をコピー & ペーストして大丈夫です。

[ORACLE_HOME]/network/admin/tnsnames.ora

...(元々の記述)

(最終行へ全文を貼り付け)

※ セキュリティのため、 tnsnames.ora の内容は記載していません。

Oracle Database ツールでの接続

SQL*Plus

tnsnames.ora に登録されていれば、あとはいつも通りネットワーク・サービス名 (net_service_name) を使用してデータベースへ接続できます。

1. SQL*Plus 起動

PowerShell

sqlplus /nolog

2. ローカル・ネーミング・メソッドによるデータベース接続

CONNECT ADMIN/[password]@[net_service_name]

ユーザ名に ADMIN 、パスワードには Autonomous Transaction Processing のプロビジョニングの際に決めたパスワードを入力します。

ネットワーク・サービス名は、Autonomous Database には予め 5 種類のデータベース・サービス名が用意されており、その中から選択する形になります。

データベース・サービス名
[database_name]_tpurgent
[database_name]_tp
[database_name]_high
[database_name]_medium
[database_name]_low

使用するデータベース・サービス名によってパフォーマンスや同時実行性が異なりますので、詳細については公式ドキュメントをご覧ください。

docs.oracle.com

データベース接続後は、通常の Oracle Database と同じように SQL を発行することができます。

SQL Developer

SQL Developer でクライアント資格証明 (ウォレット) を使用してデータベースを接続する場合は、専用の接続タイプを指定して接続を行います。

1. データベース接続の作成/選択ダイアログを開く

SQL Developer を起動し、接続の作成ボタン (以下の画像の赤枠内) を押下して、データベース接続の作成/選択ダイアログを開きます。

データベース接続の作成

2. ユーザ情報を入力

ユーザ名に ADMIN 、パスワードには Autonomous Transaction Processing のプロビジョニングの際に決めたパスワードを入力します。

接続タイプは クラウド・ウォレット を選択し、構成ファイルにクライアント資格証明 (ウォレット) ファイルを指定します。

サービスには前述した SQL*Plus と同様、事前定義されている 5 種類のデータベース・サービス名から選択します。

ユーザ情報を入力

3. 接続

あとは接続ボタンを押下すれば、 SQL Developer から Autonoumous Transaction Processing のデータベースへ接続できます。

接続後は SQL*Plus と同様に、通常の Oracle Database のように各種操作を行うことができます。

クライアントアプリケーションからの接続

その他のクライアントアプリケーションからの接続に関しては、 SQL*Plus と同様にネットワーク・サービス名を使用したローカル・ネーミング・メソッドによるデータベース接続を行うことで、特に Cloud を意識することなく使用することができるはずです。

クライアント資格証明 (ウォレット) を使用しているネットワーク・サービス名さえ指定すれば、あとは今まで通り使用できると思いますが、詳細については使用するクライアントアプリケーションやライブラリの公式ドキュメントなどを確認してください。

おわりに

クラウドというだけで何となく難しいイメージを持ってしまっていましたが、実際は Web ブラウザを介して GUI で簡単に操作・管理ができ、クライアントからの接続についても特に難しいことはありませんでした。

今まではローカルの PC に Oracle Database をインストールして使用していたため、 PC を替える度にデータベースの作成・データ移行をする必要がありましたが、クラウドへ移行したことによってそういった手間から解放されると共に、物理破損によるデータ消失のリスクも軽減することができました。

それもこれも、永久無料 (常時無償) の Oracle Cloud Free Tier という Oracle の超太っ腹なサービスがあったからこそ実現できたもので、他にクラウドRDBMS で永久無料なのは Heroku Postgres くらいしかないため、 Oracle 様には足を向けて寝られません。

Oracle Cloud は AWSGCP の影に隠れがちですが、Oracle 大好きな僕としては是非ともシェアを伸ばしていってほしいと思います。

そして、願わくばシェアが伸びた暁には、もっと Free Tier の無料枠を拡大してくれることを… (*´∀ˋ人)

【Flask】ディレクトリ構成を考える

flask-logo

追記

- 2020/09/13 -

コメント欄で msiz07 様からご指摘頂きました通り、当記事で Flask 公式ドキュメント としている参照先はすべて、正確には Flask 公式ドキュメント (本家英語版) を個人の方が和訳したもの になります。

厳密に言えば参照先は 非公式 となりますが、内容に関しては本家の英語版と同様に大変参考になるものですので、非公式であるという注釈を追記した上で引続き参照させていただいております。

msiz07 様、コメントありがとうございました!


Flask 公式ドキュメント (本家英語版)

flask.palletsprojects.com

はじめに

Flask は Python 用 Web アプリケーションフレームワークの一つで、自身をマイクロフレームワーク (microframework) と呼んでいます。

Flask 公式ドキュメント ( *1 ) にもある通り、マイクロフレームワークの意味するところは、必要最小限の機能を提供しつつも多くの拡張性を保持することを目的としており、シンプルが故に機能が不足するということではありません。

シンプルなのは良いことですが、同じ Python 用 Web アプリケーションフレームワークである Django のように決まったディレクトリ構造を持たないため、目的に応じて自由にディレクトリやファイルを構成できる利点はあるものの、一定規模以上の Web アプリを作成しようとしたり複数名での開発を行う場合はある程度決まったルールが必要です。

ということで、今回はユースケースに応じた Flask アプリケーションのディレクトリ構成を考えてみました。

TL;DR

  • 必要なことはすべて Flask 公式ドキュメントが教えてくれた
  • Prototype 用、 Web アプリ用、 RESTful API 用の 3 パターンを考えたよ
  • GitHub にアップしたよ

github.com

動作環境

OS Version
Windows 10 Pro 1909
Application Version
PowerShell 5.1.18362.752
Language Version
Python 3.8.5
Package Version
Flask 1.1.2

前提条件

  • venv で仮想環境が構築済みで、 Activate された状態である
  • 仮想環境に Flask がインストール済みである

ユースケース毎のディレクトリ構成を考える

Flask アプリケーションはモジュールとして作るか、パッケージとして作るかでディレクトリ構成が大きく変わります。

プロトタイプ開発や小規模な Web アプリであれば、必要最小限の構成でもさほど煩雑にはならないため、単一モジュールに処理を詰め込んでもいいですが、ある程度スケールすることが見込まれる場合は複数の処理を意味のある単位に分割し、パッケージとして Flask アプリケーションを作るのが定石です。

msiz07-flask-docs-ja.readthedocs.io

個人的には、機能が複数 (例えば、検索・一覧表示機能と登録・更新機能など) になる場合は、初めからパッケージとしてモジュールを分割しておいた方が、後々のことを考えると無難だと思っています。

今回はユースケースに分けて、プロトタイプ開発や小規模 Web アプリケーションをターゲットするモジュール版、一定規模を想定したパッケージ版に加え、 SPA (Single Page Application) などからのアクセスに対応する RESTful API 版の 3 パターンを考えてみました。

プロトタイプ・小規模 Web アプリケーション

エントリーポイント (FLASK_APP 環境変数) をモジュールとして、ルーティングやビジネスロジックは一つの Python ファイルにまとめて記述します。

使い捨てとなるプロトタイプや単機能の Web アプリケーションなどを想定した、さっと手軽に作れるシンプルなディレクトリ構成です。

ディレクトリ構成

/
├ instance/
│ └ config/
│    ├ development.py
│    └ production.py
├ log/
├ static/
│ └ css/
│    └ default.css
├ templates/
│ ├ base.html
│ └ greeting.html
├ tests/
├ application.py
├ requirements.txt
└ settings.py

/instance/

Flask 0.8 から導入された Instance Folders (インスタンスフォルダ) 。

バージョン管理 (Git など) に含めない設定ファイルや非公開ファイル (API キーなど) を格納するディレクトリ。

Flask のインスタンスを生成する際、 instance_path パラメータや instance_relative_config パラメータでディレクトリの位置を設定できる。

msiz07-flask-docs-ja.readthedocs.io

/log/

Flask のログ出力先ディレクトリ。

ログ出力については、この記事では触れません。

/static/

JavaScriptCSS 、画像ファイルなどの静的ファイルを格納するディレクトリ。

msiz07-flask-docs-ja.readthedocs.io

/templates/

テンプレート (HTML) ファイルを格納するディレクトリ。

Flask はテンプレートエンジンとして Jinja を採用している。

msiz07-flask-docs-ja.readthedocs.io

/templates/base.html

<!DOCTYPE html>

<head lang="ja">
  <meta charset="utf-8" />
  <link rel="stylesheet" href="{{ url_for("static", filename="css/default.css") }}">
  <title>{% block title %}{% endblock %}</title>
</head>

<body>
  {% block content %}{% endblock %}
</body>

/templates/greeting.html

{% extends 'base.html' %}

{% block title %}flask-web-app{% endblock %}

{% block content %}
<h1>
  {{ greeting }} {% if user_name %}{{ user_name }}{% else %}World{% endif %} !!
</h1>
{% endblock %}

/tests/

UNIT テスト用ファイル格納ディレクトリ。

テストについては、この記事では触れません。

/application.py

エントリーポイントとして Flask インスタンスを生成する Python モジュール。

import os
from flask import Flask, request, render_template

app = Flask(__name__, instance_relative_config=True)

# 標準設定ファイル読み込み
app.config.from_object("settings")

# 非公開設定ファイル読み込み
if app.config["ENV"] == "development":
    app.config.from_pyfile(os.path.join("config", "development.py"), silent=True)
else:
    app.config.from_pyfile(os.path.join("config", "production.py"), silent=True)

@app.route("/", methods=("GET", "POST"))
@app.route("/<string:greeting>", methods=("GET", "POST"))
def greeting_user(greeting="Hello"):
    if request.method == "POST":
        user_name = request.form["user_name"]
    else:
        user_name = request.args.get("user_name", "")

    return render_template("greeting.html", greeting=greeting, user_name=user_name)

設定ファイル

標準設定

/settings.py

application.pyapp.config.from_object() メソッドから読み込まれる標準設定情報を記述。

バージョン管理に含まれるため、公開しても問題無い設定や後から上書きされるデフォルト設定のみを記述し、データベース接続情報や各種 API キーなどの非公開情報は記述しない。

非公開設定

/instance/config/development.py

/instance/config/production.py

application.pyapp.config.from_pyfile() メソッドから読み込まれる非公開設定情報を記述。

データベース接続情報や各種 API キー、 Flask の組み込みの設定値 SECRET_KEY もここへ記述する。

development.py は開発用の設定、 production.py には本番用の設定を記述し、 app.config["ENV"] の値によって設定を切り替える。

起動方法

PowerShell でアプリルートをカレントディレクトリとして flask run を実行すると、開発用サーバが起動します。

開発用サーバ起動前に、環境変数 FLASK_APP に Flask アプリケーション (インスタンス) が生成される Python モジュールを指定し、デバッグモードを有効にするために環境変数 FLASK_ENV には development を指定します。

PowerShell

> $env:FLASK_APP="application.py"
> $env FLASK_ENV="development"
> flask run

動作確認

Web ブラウザで http://127.0.0.1:5000/Hi?user_name=hrgm を開くと、起動した Flask アプリケーションへアクセスできます。

ちなみに、今回のサンプルは URL のパラメータを表示しているので、 Hihrgm を変更すると表示内容が変わります。

中規模 Web アプリケーション

エントリーポイントをパッケージとし、 Blueprint を用いてルーティングやビジネスロジックを別モジュールへ分割しています。

msiz07-flask-docs-ja.readthedocs.io

機能単位にモジュールを分割することで、今後の拡張によってコードが煩雑になることを防ぎます。

ディレクトリ構成

/
├ app/
│ ├ models/
│ ├ static/
│ │ └ css/
│ │    ├ default.css
│ │    └ style.css
│ ├ templates/
│ │ ├ base.html
│ │ └ greeting/
│ │    └ greeting.html
│ ├ views/
│ │ └ greeting.py
│ └ __init__.py
├ instance/
│ └ config/
│    ├ development.py
│    └ production.py
├ log/
├ tests/
├ MANIFEST.in
├ requirements.txt
├ settings.py
└ setup.py

※ 前述の プロトタイプ・小規模 Web アプリケーションのディレクトリ構成 との差分のみ記述します。

/app/

Flask アプリケーションのコードを含むディレクトリ。

機能別にモジュールを分割するため、 Python パッケージとする。

/app/models/

データベース接続や Model クラスを記述したファイルを格納するディレクトリ。

MTV (Model Template View) モデルの Model に相当するファイルを格納する。

データベース関連は、この記事では触れません。

/app/views/

ルーティングや、その URL に対するコールバック (ビジネスロジック) を記述したファイルを格納するディレクトリ。

MTV (Model Template View) モデルの View に相当するファイルを格納する。

/app/views/greeting.py

from flask import Blueprint, render_template, request

greeting = Blueprint("greeting", __name__, template_folder="templates")

@greeting.route("/", methods=("GET", "POST"))
@greeting.route("/<string:greeting>", methods=("GET", "POST"))
def greeting_user(greeting="Hello"):
    if request.method == "POST":
        user_name = request.form["user_name"]
    else:
        user_name = request.args.get("user_name", "")

    return render_template(
        "greeting/greeting.html", greeting=greeting, user_name=user_name
    )

/app/__init__.py

本来、 __init__.py には Python パッケージの初期化処理を記述しますが、特に Flask アプリケーションのエントリーポイントとなるパッケージでは、 Application Factory となる create_app() メソッドを定義します。

また、 Blueprint によって分割された views ディレクトリ配下の greeting モジュールから Blueprint オブジェクト (greeting) を import し、 Flask アプリケーションへ登録しています。

import os
from flask import Flask

def create_app(test_config=None):
    app = Flask(__name__, instance_relative_config=True)

    # 標準設定ファイル読み込み
    app.config.from_object("settings")

    # 非公開設定ファイル読み込み
    if app.config["ENV"] == "development":
        app.config.from_pyfile(os.path.join("config", "development.py"), silent=True)
    else:
        app.config.from_pyfile(os.path.join("config", "production.py"), silent=True)

    if test_config is not None:
        # テスト用設定を上書き
        app.config.from_mapping(test_config)

    from .views.greeting import greeting

    app.register_blueprint(greeting, url_prefix="/greeting")

    return app

/MANIFEST.in

当プロジェクトを配布・インストールする際に必要となるマニュフェストテンプレート。

/setup.py

当プロジェクトを配布・インストールする際に必要となる setup スクリプト

起動方法・動作確認

アプリルートで flask run を実行して開発用サーバが起動するのは前述の プロトタイプ・小規模 Web アプリケーションの起動方法 と同じです。

ただし、開発用サーバ起動前に設定する環境変数 FLASK_APP には、 Application Factory が定義されている Python パッケージを指定します。

PowerShell

> $env:FLASK_APP="app"
> $env FLASK_ENV="development"
> flask run

動作確認は前述の プロトタイプ・小規模 Web アプリケーションの動作確認 と同様です。

RESTful API

基本的には 中規模 Web アプリケーション と同様のディレクトリ構成ですが、レスポンスはすべて JSON 形式となるため、 static ディレクトリや templates ディレクトリは省いています。

ディレクトリ構成

/
├ api/
│ ├ models/
│ ├ views/
│ │ └ greeting.py
│ └ __init__.py
├ instance/
│ └ config/
│    ├ development.py
│    └ production.py
├ log/
├ tests/
├ MANIFEST.in
├ requirements.txt
├ settings.py
└ setup.py

※ 前述の プロトタイプ・小規模 Web アプリケーションのディレクトリ構成中規模 Web アプリケーションのディレクトリ構成 との差分のみ記述します。また、 Flask アプリケーションのディレクトリ名は api に変更しています。

/api/views/greeting.py

URL にバインドされたコールバック関数の戻り値を dict (辞書型) にすると、レスポンスの mimetypeapplication/json となり、 JSON データとして送信されます。

from flask import Blueprint, request

greeting = Blueprint("greeting", __name__)

@greeting.route("/", methods=("GET", "POST"))
@greeting.route("/<string:greeting>", methods=("GET", "POST"))
def greeting_user(greeting="Hello"):
    if request.method == "POST":
        user_name = request.form["user_name"]
    else:
        user_name = request.args.get("user_name", "")

    return {"greeting": greeting, "user_name": user_name}

起動方法・動作確認

前述の 中規模 Web アプリケーションの起動方法・動作確認 と同様。

GitHubリポジトリ

今回まとめた 3 パターンのディレクトリ構成は、 GitHubリポジトリを公開しています。

今後 Flask で開発をする際はプロジェクトテンプレートとして使用し、使いながらその都度、修正・改善をしていこうと思います。

github.com

おわりに

Flask アプリケーションのディレクトリ構成を考えるにあたり、様々なサイトを参考にさせていただきましたが、必要なことは Flask 公式ドキュメント にすべて書いてありました (当たり前) 。

僕は DjangoRails といった Web アプリケーションフレームワークをほんの少しかじった程度ですが、そういった大規模開発に対応できるフレームワークを模倣することで、 Flask の標準機能だけでもある程度の開発規模に耐えうるディレクトリ構成が実現可能だと思いました。

プロトタイプや小規模 Web アプリケーションの開発には手頃でちょうど良いと書きましたが、 Django よりも Flask の方が制約や規約が少なく自由度が高いため、機能数や画面数は少ないけれど複雑で特殊な処理が多いってケースには、多少規模が大きくなっても逆にフィットするかもしれません。

保守は大変になりそうですけど。。

いずれにしても適材適所なので、現在の Python の Web アプリケーションフレームワークである Django と Flask の二強体制は、開発規模によって使い分けるにはちょうど良い形なのかなと思っています。

が…!

Flask について調べた直後ではありますが、最近は巷で話題の FastAPI に興味津々です!!

fastapi.tiangolo.com

近いうちに使ってみたい ( º﹃º` )

*1:参照先は本家の Flask 公式ドキュメント (英語版) を個人の方が翻訳した日本語版。以降、 Flask 公式ドキュメントと記述されているものはすべて同様。

【働き方】2020 年上半期のリモートワークを振り返る

リモートワーク

はじめに

キラッキラしたイケてる Web 系エンジニアみたいに、軽快なバックグラウンドミューズィックが流れるシャレオツなカフェや自宅のデスクで MacBook を開き、クールなフェイスでホットなラテを飲みながら颯爽とコードを書きたい。

そう思っていた時期が僕にもありました。

近年は現実を知ったこともあり、今は自分にできることを積み重ねていこうと心に決めたわけですが、それでもずっと思っていたことがあります。

リモートワークがしたい!!

時は金なり (Time is money) と昔の偉い人が言った通り、自宅と会社の往復に毎日 2 時間以上かけるのは、どう考えても時間を無駄にしています。

そうは言っても SES を生業とする SIer の弊社は、多くのケースにおいて常駐先の勤務体制に従うほかなく、リモートワークは夢のまた夢という感じでした。

しかし 2020 年に入り、受託開発やコロナ渦による影響で思いもよらずリモートワークをする機会を得て、フルではないものの一部リモートワークを 7 月現在も約半年間続けることができているので、ここで一度振り返りをしておこうと思い、このエントリーを書いています。

リモートワークの内容

受託開発

期間 時間 場所 備考
2020 年 1 月 ~ 4 月 定時後 (残業扱い) 自宅 フルリモート (必要に応じて対面でのミーティング)

2020 年 1 月下旬、普段は客先常駐のプロジェクトに参画している僕ですが、それと並行して受託開発のプロジェクトにリモートワークで参画することになりました。

開発環境は Google Cloud 、メンバーとのやり取りは Slack を使用し、会社から帰宅後に自宅でリモートワークという形です。

作業する日と時間は各自の裁量に一任されましたが、 36 協定を遵守した残業扱いなので決して違法ではありませんw

約 3 ヶ月間のプロジェクトで初めてのリモートワークでしたが、日中は普通にフルタイムで会社に出社しているので、感覚的には自宅でプライベートなコードを書いている時とあまり変わらなかったです。

個人開発と違う点は、チーム内でコミュニケーションを取りながら開発を行う必要があることと明確にスケジュールが決まっていること (納品する相手がいるという意味) で、チーム内でのコミュニケーションについてはいくつか課題もありました。

課題があるとはいっても、肝心のプロジェクトの方は初めてのリモートワークにも関わらず無事にリリースまで完了し、リモートワークでも十分結果が出せるということを証明できました。

【課題】チーム内コミュニケーション

裁量労働によるコミュニケーションロス

コミュニケーションツールとして Slack を使用しましたが、 普段の常駐先プロジェクトでも MicrosoftTeams を使用しているので、ツールの違いによる影響はほとんどありませんでした。

問題はツールではなく運用する人の側にあり、作業する日と時間が各自の裁量に任せられたことで、優先度の高い確認事項があったとしても返答がいつ来るか分からないということが度々発生しました。

これが定時内 (所定の就業時間内) を前提としたリモートワークであれば、当日中か遅くとも翌営業日には何らかの返答を期待できますが、定時後の残業扱いとなっている以上、連絡した相手がいつ確認するか分かりません。

そもそも残業時間のみを前提とした働き方がイレギュラーだというのは重々承知していますが、顔の見えない非同期コミュニケーションにおいて、いつ返答がくるか分からないのはなかなかストレスが溜まるものでした。

SlackTeams はメンバーのログイン状況が分かるようになっているので、双方がオンラインであればチャットはとても有効なコミュニケーションツールになりますが、一方がオフラインの場合はチャットもメールも、なんなら留守録のメッセージであっても、いつ気付いて返信をくれるか分からないという点においては大差無いということになります。

これはリモートワークに限った話ではありませんが、裁量労働のフルリモートワークでは、他者へ確認・調整が必要なことは先を見越して事前に連絡を済ませるなど、自分の作業が円滑に進むようにセルフマネジメントを行うことが特に重要だと感じました。

今回はコミュニケーションツールとして Slack しか使用しませんでしたが、次回からは緊急度に応じた複数の連絡手段を用意したり、チーム内で各メンバーの数日~ 1 週間先くらいまでのスケジュールを共有するなどの、ガチガチにならない程度の運用ルールを決めるべきかと思います。

SES

期間 時間 場所 備考
2020 年 5 月 ~ 継続中 定時内 自宅 週 2 ~ 3 日 (残りの平日は出社)

2020 年 4 月、新型コロナウイルス (COVID-19) の影響により発令された緊急事態宣言を受け、僕が参画するプロジェクトも客先の意向で 5 月中旬から本格的にリモートワークの導入が始まり、 7 月現在も週 2 日は自宅でリモートワークを行っています。

SES でリモートワークってあまり聞いたことが無いと思いますが、貸与されたノート PC から VPN で社内ネットワークへ接続して業務を行うため、開発環境やその他は出社した場合と比べて何ら変わりありません。

勤務時間も出社時と同様なので、リモートワークであっても定時内はメンバー全員がオンラインになっています。

コミュニケーションツールは MicrosoftTeams を使用していますが、前述の受託開発プロジェクトとは違い、コミュニケーションロスはほとんど発生していません。

現時点での唯一の課題は、社内ネットワークへの接続とセキュリティを確保するための VPN が非常に低速な (そもそも社内ネットワーク自体も遅い) ことで、実用上に大きな問題は無いものの、 Teams のビデオ会議はネットワーク帯域を圧迫するという理由から使用が禁止されています。

未だ新型コロナウイルスの問題は収束しておらずリモートワークの終了時期は未定ですが、あくまでも緊急的な措置としてのリモートワークなので、おそらく今以上の環境の改善は期待できないと思います。

しかし、前述の受託開発と同様、リモートワークであっても環境さえ整えば、出社時と比べて遜色ないパフォーマンスを発揮できるということが分かりました。

【課題】ネットワーク (通信環境)

ネットワーク帯域幅の不足

リモートワークでは作業の多くがネットワークを介して行われることから、十分なネットワーク帯域幅が確保されていないと、それがボトルネックとなって業務に支障をきたす可能性が出てきます。

自宅でリモートワークをする場合、一般的には 1 Gbps 以上の光回線のインターネット接続を契約しているケースが多いと思いますので、その点は問題無いと思います。

しかし、多くの企業はセキュリティ等を考慮して VPN専用線を使用することが前提となっており、その帯域幅が問題になってきます。

この問題の難しい点は、ネットワーク帯域幅の確保はコスト増に直結するため、個人やチームではなく会社を動かさなければならない点にあります。

これはシンプルな割に解決が難しく、いかに会社の上層部を説得できるかがポイントになります。

リモートワークをしてみて

単純な感想

前々からリモートワークがしたいと考えていた僕が、実際に約半年間のリモートワークをしてみて言えることは、

リモートワーク最高~~~~~~~~~

リモートワーク最高

の一言に尽きます。

朝ご飯はちゃんと食べられるし、子供を学校に送り出すこともできるし、仕事中に淹れたての珈琲は飲めるし、疲れたらゴロンと寝っ転がれるし、何より通勤時間がゼロになるので今まで通勤に充てていた時間を有効活用することができます。

業務上の問題も現時点では出ていないですし、個人レベルの話ではありますが、部分的なリモートワークであれば導入は難しくないなと思いました。

リモートワークのメリット

通勤時間がゼロ

通勤時間がゼロということは、今まで通勤にかかっていた時間を別のことに充てられることを意味します。

単純に自分の時間が増えるので、勉強をするもよし、家族との時間を増やすのもよし、体調が悪いときは休息を取ることもでき、とにかく QOL が爆上がりします。

また、エンジニアであれば仕事モードの集中力を保ったまま、業務での開発から個人開発へシームレスに移行できることにメリットを感じる方もいるのではないでしょうか。

次で述べている私用 PC の併用もあり、アウトプットの時間と質の確保にも大きく寄与します。

私用 PC を併用できる

今まで、有用な情報が記載されているサイトのブックマークや公開情報をまとめた自分用資料は会社の PC にしか存在せず、たとえ個人情報などの機密情報が含まれていなくても、持ち出しや印刷しての持ち帰りは不可能でした。

また、 SES では多くの場合、外部ネットワークへのアクセスが監視・制限されており、下手なサイトにアクセスすると呼び出されて事情聴取を受けることも間々あります。

業務要件や規則によって違ってくるとは思いますが、リモートワークであれば業務用に PC を貸与されていても、調べものは私用 PC を使用することができるので、調べた公開情報を自分の PC に残して、あとで改めて勉強のために見返したりまとめたりすることができます。

これは客先常駐による弊害の一つで、自身のスキルアップを妨げる一因にもなっていましたが、リモートワークではキレイさっぱり取り除かれました。 (スキルアップできるとは言ってない)

リモートワークの課題

ここはあえてデメリットではなく解決が可能な課題と書きますが、今後想定されるものとしては 新人教育 が課題の一つになってくるかと思います。

今回のリモートワークはすべて見知ったメンバー同士のプロジェクトであったため、たとえ顔が見えなくてもテキストから大体の表情や口ぶりまで想像することができましたが、新規参画メンバーやそれこそ新入社員を相手にする場合は相当な配慮が必要になるでしょう。

顔の見えない相手と非同期的にテキストベースでコミュニケーションを取るには、誤解を与えない言い回しや簡潔に用件をまとめる文章力などに加え、相手の心情を汲み取る気遣いも要求されます。

特に教育の場にあっては、対面であれば態度や雰囲気から相手の理解度などを何となく察することができますが、リモートワークではそうもいきません。

教えた内容の理解度を都度確認する、教育を受けている側も態度や表情では何も伝えられないので、はっきりと「分かった」「分からない」の意思表示をするなど、人によっては遠慮してしまうケースが出てくるかもしれません。

そもそもすべてをリモートで行う必要はないので、集合教育やビデオ会議も適宜取り入れ、チームに合った最適解を見付けることが大切なんだと思います。

おわりに

この半年間の体験は、何故今まで律儀に出社していたのかと後悔さえしてしまうほど (規則だからです) で、リモートワークの魅力を感じるには十分過ぎるものでした。

同時にいくつかの課題も見えてきましたが、これらは解決不可能な問題ではなく、個人やチームの努力と会社の協力さえ得られればいくらでも解決は可能です。

今回振り返った内容を踏まえ、 2020 年下半期は弊社の正式な制度としてリモートワークを導入できるように、働きかけを行っていく所存です!

弊社では、というか僕が、一緒に開発エキスパートチームを作ってくれる仲間を募集しています!

現在構想中の開発スペシャリストチーム (名前ブレブレ) は、各領域のエキスパートをメンバーとする少数精鋭チーム (予) で、リモートワーク (予) 中心に開発を行うことを予定しています (すべて予定)。

気になる方は是非ご連絡をお待ちしています ٩(ˊᗜˋ*)و