fuzzy study

仕事・趣味で勉強したことのメモ

システムインフラの変遷

インフラエンジニアとして7年ほど過ごしてきたのと、今サーバレスシングルページアプリケーションについて勉強していて、サーバレスに至るまでいろいろあったよなあと振り返る機会があったので、システムインフラの変遷を感じるままに書いてみました。
(昔の)ITインフラについてあまりよく知らない人向けくらいに書いています。

※物理環境からサーバレスアーキテクチャに至るまでの変遷を、私個人の視野・視点から非常にざっくり、かいつまんで記載しています。歴史的に不正確・不十分な記述がある可能性が大いにありますのでご注意ください。また、そういった点がありましたら是非コメントください。

物理環境

最も単純なインフラでは、物理的なサーバそれぞれに1つのOSをインストールし、個別の役割を持ったサーバを構築してシステムを構成していました。

f:id:fuzzy0:20190118145333p:plain
物理環境(オンプレミス)

仮想化

VMwareKVMHyper-V等のサーバ仮想化技術により、1台の物理サーバ上に複数の独立したOSを仮想マシンとして動作させることが可能になりました。*1
ハードウェアそのものの「物理層」と、ユーザから見える「論理層」を分離したことになります。

この頃画期的だったのは仮想アプライアンスです。あらかじめ必要なソフトウェアや設定を導入した状態の仮想マシンイメージを提供するもので、環境のセットアップが格段に簡便になりました。今のAWSでいうAMIがイメージに近いです。

仮想化は「物理サーバの集約によるコスト削減」を主として導入が進んだ認識ですが、それに加えて

  • 物理層と論理層の分離により、インフラレイヤでも柔軟な設計変更が可能になった
  • 論理層の構築作業をのプログラムにすることにより、より強力な自動化が可能となった(Infrastructure as Code)

といったメリットが目立ってきました。 さらに加えて、サーバ(CPU、メモリ、ローカルディスク)だけでなく、ネットワークや共有ストレージのハードウェアもこれまで以上に仮想化が進み、システムの構成要素のほぼ全てが仮想化の恩恵を受けるようになりました。

f:id:fuzzy0:20190118145336p:plain
仮想化

クラウド

上記のような仮想化技術のメリットは、物理層の集約規模が大きくなればなるほど享受しやすくなります。同じ構成・仕組みで共通的なオペレーションを自動化すれば、コスト削減効果が高くなるからです。(スケールメリット
かつ、論理層はインターネット経由でも操作できるため、クラウドサービスを提供する企業が発展しました。
現在の主要なクラウド業者といえば以下3社ですね。もちろんほかにもありますが。

  • AmazonWebServices
  • GoogleCloudPlatform
  • Microsoft Azure

クラウド環境では

  • (当然)機器調達やラッキング、配線作業などはない
  • 設計においても物理層を意識する必要はほぼない
  • 自動化の仕組みがあらかじめ提供されている

といったことから、従来には比べ物にならない早さでシステム構築できるようになりました。

AWSを例に、Web3層アーキテクチャを構成する場合に利用するサービスを(超ざっくり)図にします。

f:id:fuzzy0:20190118145329p:plain
クラウドAWS

これらのうちRDSは、リレーショナルデータベースのフルマネージドサービスです。

フルマネージドサービスは、従来高度な技術をもったインフラエンジニアが行っていた、インフラまわりの非機能的な設計や作業の多くを裏で自動的に行ってくれるサービスです。
フルマネージドサービスを活用すると煩わしい環境管理作業にコストをかけずにシステム運用でき、クラウドサービスの大きな利点となっています。
DevOpsという文化も、こういった「インフラをコード化して手間をかけずに運用する」ことを前提に置いたときに生まれたものと思います。

ただし、自動化が進んでいるとはいえ、論理的なサーバを持っていることには変わりないため、ネットワーク配置、冗長化、バックアップあたりの設計には、従来と同様の考慮が必要です。

フルマネージドサービスの中には論理的なサーバを(ユーザ側では)持たないサービスもあります。AWSで言うとS3、DynamoDB、Route53など。
こういったサービスのみを利用したアーキテクチャが、サーバレスアーキテクチャです。
サーバレスアーキテクチャでは、ユーザから見えるのはAPIなどのエンドポイントのみなので、ユーザが論理的なサーバを持つことはなくなり、環境管理についてはもはや全く気にする必要がなくなります。

AWSを例にすると、サーバレスアーキテクチャの中心を担うのがLambdaです。 Lambdaは、特定の機能ではなく、任意のコードを実行するサービスであるため、APサーバの役割を果たします。 このような「任意のコード実行のためのフルマネージドサービス」の登場が、サーバレスアーキテクチャ発展の最大要因と思います。

サーバレスアーキテクチャではAPI等でサービスを利用するため、クライアントサイドのSPAのロジックに直接組み込むことができ、結果としてサーバレスSPAを構築できます。

f:id:fuzzy0:20190118145326p:plain
サーバレスアーキテクチャ

サーバレスアーキテクチャの内部技術として使われるものの一つにコンテナがあります。
コンテナはサーバ仮想化と似ていますが、サーバ仮想化ではOSのイメージ(OSをインストールする先のディスク領域)が各VMで独立なのに対し、コンテナではOSのカーネルは共有し、イメージの差分データと、そのOS上で動作するプロセスを独立させて動作させる点で異なります。

コンテナでは各コンテナで独立している部分が少なくなるため、データが軽量かつ起動が高速という特徴があります。 Lambdaはこれを利用することで、ユーザが動かしたいときだけ動くサーバ(のように見えるプロセス)を実現しています。

おわりに

システムインフラの変遷について書いてきましたが、当然あとの方のアーキテクチャが正義というわけではなく、メリデメはあります。例えばサーバレスアーキテクチャでは、インフラのアップデートが比較的早いスパンであることが多いにも関わらず、アプリ側が必ずついていかなければならないことや、1ベンダーに依存するシステム構成になりやすいことがあると思います。適したものを選ぶ必要があるのはずっと変わりません。

最近はクラウドから入ったクラウドネイティブな方も多いと思います。そういう自分も仮想化ネイティブでしたが、物理→仮想化よりクラウドのほうが大きな変化に感じているので、クラウドにしっかりキャッチアップしていきたいです。

サーバレスアーキテクチャのように、どんどんインフラ側にかけるコストが低減され、よりプロダクトにかけるコスト/技術が重要視されていくので、インフラエンジニアとしては徐々にでもフロント側へスキルを寄せていかないとなあと思う次第です。

*1:ちなみに仮想化やコンテナ技術自体はメインフレームの頃からあったそうです。まあ、タイムシェアリングシステムもファイルシステムも、仮想化といえば仮想化ですしね。

2018年の振り返り(AI・AWS・AR)と今年の目標

2018年を振り返って、取り組んだこと、学んだこと、などを、技術観点で棚卸ししておこうと思います。

AI編

AIブームにあやかり、昨年に引き続きAI系の仕事に関わってきました。
AIっていうけど要は機械学習のPoCです。

2017年の夏ごろから2018年の3月までは、Tensorflowを使って基本的なMLPAPI化したり、 AutoEncoderやLSTMを使ったデータ分析の勉強をしたりしていました。
2018年4月からは、chainerで実装された画像認識系モデルを使って推論かけたりしていました。

主に技術的要素について経験したことを振り返ります。

機械学習

最小二乗法からはじまり、DeepLearningについてもMLP、CNN、RNN、AutoEncoderの基礎理論の勉強と実装をしました。
もともと画像認識系のことを大学院の研究で行っていたこともあり、ある程度は知っているつもりでしたが、だいぶ浅かったです。。
今年、仕事でも関わりつつ何冊か本を読んだので、入門書に載っている内容程度なら会話が成り立つくらいには経験できたと思います。

理論的なことでいまだに疑問がぬぐえていないのが、 ニューラルネットワークに入力するデータは、連続値データとカテゴリカルデータが混ざっているケースが多々あるが、それでよいのか、ということ。 これはやはり専門家に聞いてみたいものなのですが、例えばAutoEncoderで異常検知的なことをしたいとして、値域として0~10000を取る次元と、5パターンの値を取るカテゴリカルデータをone-hotにした次元(5つ)を、同じベクトルにくっつけて入力して、意味のある学習が行えるものなのか?ということです。
前処理として正規化したり、ニューラルネットワーク側でBatchNormalizationしたりはするとしても、どうも何とも言えない違和感があるんですよね。
特に最後に異常の度合いを測るとき、連続値とカテゴリカルデータは本来異なる定義が必要なのに単純に出力ベクトルのノルムで測りがちで、いいの?と思うんですよね。
なんかご存知の方いたら教えてほしいです。

しかし、こういった理論的なこと含め、新たなモデルを作るレベルの取り組みは、単に機械学習の基礎を理解してフレームワークで実装できる程度ではなく、より高度な理論背景理解と実装力が必要だと感じています。
自分のレベルだと、デファクトになっているモデルをリファレンス見ながら実装してみる程度までなので、最新の論文を理解してその通りに実装して効果を確かめるとかいったレベルに達するには継続的な勉強と経験が必要だと思いました。

機械学習関連で読んだ書籍

ITエンジニアのための機械学習理論入門

ITエンジニアのための機械学習理論入門

DeepLearning以前に機械学習の基本を学ぶために読みました。大変読みやすい文章で理解が進みました。 詳しい数式での解説はコラムに分けられているのも、レベルを調整しながら読めたので好印象でした。

まずはこの一冊から 意味がわかる統計解析 (BERET SCIENCE)

まずはこの一冊から 意味がわかる統計解析 (BERET SCIENCE)

ずっと前に統計を勉強しようと買った本だったのですがずっと積読していて、今だと思って読みました。 統計検定2級くらいの内容なのだと思います(受けてないけど)。検定とかあまり実務で使うことはないのでなかなか身にはつきにくいですが、この本のおかげでおおよそ統計の基礎を把握できました。

いわずと知れたDeepLearning入門書ですね。こういった、フレームワークを使わずにスクラッチで書くことで原理を理解するタイプの本は、しっかり理解したいトピックの入門には最適だと思います。
本書ではRNNには触れられていないので、続編のゼロから作るDeep Learning②ー自然言語処理編も読むとよさそうですね。私はまだ読んでません。

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

ニューラルネットワークの基礎理論に加え、AutoEncoder、CNN、RNN、ボルツマンマシンまで理論的に解説されています。
私はRNNまで頑張って数式を追って読んだものの、LSTMから数式がよくわからなくなり、ボルツマンマシンは挫折しました。。

画像認識 (機械学習プロフェッショナルシリーズ)

画像認識 (機械学習プロフェッショナルシリーズ)

画像認識として括られる物体認識や物体検出について、DeepLearning以前の手法からDeepLearningを用いた近年の手法まで順を追って説明されている良書でした。

機械学習関連でお世話になったpythonパッケージ

  • numpy
    • fancy indexingが素敵でした。
  • pandas
    • データの前処理によく使う。
    • pandas plot と言われる、可視化機能も付いている。
  • matplotlib, seaborn
    • 可視化系は他にもbokeh, plotly, holoviewsなどなどたくさんあり、一長一短という感じ。肌に合うものを選ぶのがよさそう。
    • 参考:slideship.com
  • scikitlearn
  • Tensorflow
  • chainer
  • jupyter notebook

データ分析・可視化→データ前処理→学習→(モデル保存→モデルロード)→推論、の流れのどこに何を使うか、いろいろ試して使いやすいものに慣れていくと作業が楽になりそうです。

Tensorflow

DL実装技術として、Tensorflowに触れました。
TensorflowはGoogleが開発したフレームワークで、おそらく世界的に見て現在最もよく使われているDLフレームワークなのではないでしょうか。

Tensorflowは、業務ではv1.1を使い、その後v1.7くらいまでは追っていたけど使わなくなってからは追えてないです。
Tensorflowの低レベルAPIを一通り学んだあと、Kerasを使い始めましたが、 もうKerasを使わない実装は面倒すぎて考えられないです。 TensorflowはもともとDefine and Run の書き方でしたが、今後はDefine by Run で書けるようになるEager modeがデフォルトになるようなので、Kerasと組み合わせてより使いやすいフレームワークになっていくと期待しています。 データのロードや前処理などのモデル構築以外のAPIも整理されてきているみたいですし。
もうちょっと追いたいですが、最近は業務上あまり関りがない。。

chainerは読む程度に触れましたが、Tensorflowよりわかりやすくとっつきやすい印象がありました。 chainerは日本産のDLフレームワークで、Define by Run を最初期に採用したことで有名です。 研究やPoCではこちらのほうが使いやすいと思います。
プロダクション環境になると、Tensorflowのほうが盤石な印象。 Eager mode + Kerasで書きやすくなるなら、Tensorflowに分があるかもしれないですが。

他、pytorchも気になっていたもののほぼ触れることはありませんでした。流れてくる情報を見ていると、chainerをforkして開発されたのでDefine by Run で書きやすいとか、Tensorflowより実行速度が速いとか、いい噂をいろいろ聞くので、今後注目です。

Tensorflow関連で読んだドキュメント

当時はほとんど書籍も出ていなかったので公式ドキュメントばかり読んでいました。
ものすごい速さでアップデートされたので、ついていくのに精一杯どころか完全に置いて行かれました。

また、日本だとchainerの記事が多い中、Tensorflowによく言及されているこちらのブログをよく拝見しました。 Tensorflowに限らず、機械学習関連の情報をたくさん発信してくださっていて、参考になりました。

www.hellocybernetics.tech

python

2017年夏から本格的にpythonを勉強しました。

もともとC++, Javaなどの静的型付けのコンパイル言語*1しか十分には使えなかったので、pythonで初めてスクリプト言語にがっつり入門し、いろいろ衝撃を受けました。
詳しい内容は下記記事で。 fuzzy0.hatenablog.com

pythonとR

統計・機械学習分野の言語としてはpythonとRがほとんどなわけですが、

  • python : 汎用プログラミング言語なので応用幅が広い。文法がわかりやすく、読みやすい。Rに比べ処理が速いことが多い。
  • R : 統計等の数値計算に適した言語設計であり、特化すれば学びやすい。統計分野の既存ライブラリが充実している。環境構築が簡単。

といった特徴があると感じています。(Rは他人のお手伝いでほんのちょっと触っただけですけどね。。)
Rだとread.csv/write.csvによるcsv読み書きが遅いとか、 行ごとのfor文処理が遅いので行列演算を駆使すべしとかある*2ので、書き方には要注意です。

PypeRでpythonとRを連携

pythonに慣れると、Rを使いたくなる動機は「統計分野の既存ライブラリが充実している」のでそれを使いたい、というくらいになるのですが、 PypeRというpythonパッケージを使うと、pythonとRの間でデータ授受やスクリプト・関数の呼び出しができるようになります。 メインの処理をpythonで書いて、必要な関数をPypeRでRから呼ぶようにすると便利そうです。
ただし、R側でグラフを出力するなどの描画処理をしている場合は、以下どちらかの方法を採る必要がありそうです。

  • 描画に必要なデータをpython側へ持ってきてpythonで描画(持ってくるときにR知識が結構必要になるかも)
  • R側で描画したデータを画像として保存

MLOps

機械学習を軸としたシステムの運用を回す取り組みや仕組みを、DevOpsに倣いMLOpsというらしいです。
今後はPoCにとどまらず、実際にシステム導入して運用を検討するフェーズに入る企業も多いことと思いますので、 MLOpsに関する話題はこれから増えていくと思います。

個人的に今後MLOpsで議論のポイントになりそうだなあと思うことは以下の点です。

  • オンプレとクラウドどちらを採るか
    • ことDeepLearningはマシンリソースが大きくなりがち、かつGPUの高可用性設計などこなれていないノウハウが必要となるので、オンプレはハードルが高い印象。
    • セキュリティ面の懸念をクリアし、クラウドにシフトしていく流れが主流になるのではないか。
  • 学習データと学習済みモデルの管理の仕組み
    • どの期間のデータを使って、どのくらいの頻度で、どのくらいの時間をかけて学習するのか。学習済みデータの保持期間はどうするか。精度が悪いときはフォールバックできるようにするのか。などなど
    • 各システム個別の一番のチューニングポイントになりそう。
    • 機械学習アルゴリズム・性質も理解していないと設計できないポイントなので、高い技術が求められそう。

AWSなどクラウドサービスでは、機械学習関連機能をAPI的に使えるサービスに加え、 自前のモデルを学習してサービスとしてAPI提供する基盤を作るところまでを一気通貫に効率化するサービスも提供しています。(AWSのSageMakerなど)
自前でやるのはめんどうなので魅力的なサービスだと思っています。

その他の取り組み

AWS

AWSの資格であるAWSソリューションアーキテクトプロフェッショナル(AWS SAP)を取得しました。

AWSについては本格的な仕事で関わったことがあるわけではないのですが、社内のちょっとした取り組みで使ったのと、 もともとインフラエンジニアとして仮想化基盤周りに関わっていたので、興味があったという感じです。

AWS、というかクラウドは、今特に話題なのはハイブリッドとサーバレスだと思います。
AWSのいいところはアプリ開発者目線でインフラをよく知らなくても組めるサービスが次々と出てくるところで、 特にサーバレスアーキテクチャはほぼインフラを気にする必要なくシステムが組めるのでワクワクします。 私は主にインフラエンジニアとして業務に関わってきましたが、 今後はフロントエンドもちゃんとやってサーバレスでシステムくみたいですね…

今、サーバレス関連で下記書籍を読んでいます。学んだことをブログにも随時上げていきたいと思っています。

VR/AR

これもAWSと同じで本格的な仕事で関わったことがあるわけではなく、社内のちょっとした取り組みでUnityとHololens、ARCoreに触れました。

HololensについてはHoloAcademyで一通り操作を学びました。

docs.microsoft.com

Unityは以下の本で学びました。

Unityの教科書 Unity 2017完全対応版

Unityの教科書 Unity 2017完全対応版

作ったアプリは

です。

Unityの基本的な使い方は把握できました。
学生のときはOpenGLOpenCVARToolkitとか使ってC++で頑張ってアプリ作ってたので、Unityの高機能さには驚きました。いい時代です。

振り返りまとめ

来年も機械学習に関わっていくかはわかりませんが、機械学習理論と実装の基礎を身につけられたし、AIに対する市場の期待感や開発環境面の事情を体感することもできたので、いい経験ができた一年でした。

クラウドついては、AWSに限らず関わっていきたいです。特にサーバレスアーキテクチャはしっかり取り組んで身につけたいです。

ARはエンタープライズとしてはまだ市場が見えないですが、趣味で薄く長く取り組んで行きたいです。ちょっとしたゲームとか作りたいな。

今年の目標

  • TOEIC 800点
  • ブログを月8本書く
  • Androidアプリを作れるようになる
    • ストアに上げられるようなアプリを2つ作る
  • MLOpsについて掘り下げて要素技術を身に着ける
    • きっと掘り下げていくとサーバレスやマイクロサービスに行き着くはず
  • 読書を月1冊し、感想を書く

がんばります。

*1:型については「強い型付け」「弱い型付け」って言葉を知った! – Chomado – Madoka Chiyodaが詳しかったです。

*2:これはpythonでnumpyやpandas使ったりしても同じですが、「遅い」のスケールが違いました

プログラミングに向いている人向いてない人

プログラミングに向いている向いてないっていう議論を見かけたので、ちょっと思ったことを書いてみます。

自分が思うに、プログラミングに長けた人が持っている力には以下のようなものがあると思います。

  • 書き上げる力
    • プログラミング言語の基本的知識
    • 周辺ライブラリの存在と使い方の知識
    • エラーやバグ調査の効率的な方法の知識
    • 開発環境構築の知識
  • 設計する力
    • 各言語における仕様や特性の理解
    • 読みやすさやメンテ容易性を意識した書き方の知識
    • エラーやバグが発生しにくい(テストしやすい)書き方の知識
    • 性能を考慮した書き方の知識
  • 幅広いアーキテクチャパラダイム、開発手法に対応する力

これらを身につけるために必要と思う素質は、

  • 書き上げるためには
    • 具体的な目的を持つこと
    • 体で覚えるくらい飽きずに繰り返し作業できること
    • うまく進まなくても根気よくやること
  • 良い設計のためには
    • 論理的に考えること(パズル的な)
    • 自分の作ったものを客観視できること
    • 他人のコードに興味を持つこと
    • 丁寧に進めること
  • 対応力のためには
    • 興味を絶やさないこと

初心者のうちはとにかく同じようなものでいいから繰り返し書く、のが効率は悪いかもしれないけど身にはつきますね。大昔C++書いていたころは、VisualStudioの吐く意味不明エラーメッセージに対する対応方法をほぼ暗記していたような記憶があります。。

良い設計をするには書く経験よりも読む経験を積むほうがいいのかなとも思います。そういう意味で、作ることばかりに気を取られず「他人のコードに興味を持つ」のは素質の一つと思います。

プログラミング教育としては、

  • 具体的な目標を持たせ、
  • 繰り返し、かつ飽きずに取り組める題材を用意し、
  • 丁寧に教えて完成までフォローし、
  • 他人のコードと見比べてより良く書くにはどうしたらよいかを考えさせ、
  • 考えた結果をコンピュータサイエンスの背景と照らし合わせて理解を深め、
  • 手を動かしてリファクタリングする

というフローを踏めたら最高かなと思いました。


とここまで書いてみて、大元の議論はもっと基本的なレベルに対する議論だったのではないかと思い直しました。

forとかifとか、変数とか型とか、そういうレベルで向いてる向いてないを議論するなら、まずは書いていて楽しいと思えるかどうかかなと思います。
自分は未だに、自分が書いたコードが動くだけでどんなに単純なプログラムでも楽しさを感じます。(別に自分が「向いている」とは思いませんが)
じゃあどうして楽しいのかというと、自分の場合は、ものを作る力を得たというワクワク感が楽しいのだと思います。ものを作りたいというモチベーションがある人のほうが楽しみやすいでしょう(当たり前か
一方で、具体的に作りたいものが思い描けていないとどこかでむなしくなります。どんなに手を動かしてもものが出来上がらないので。そういう意味で、目的を具体的に持つことや根気は必要な素質かなと思います。

しかし近年は(いや、昔からそうなのかもしれないですが)、言語そのものというよりも、作ろうとしているものの仕組みや周辺知識のほうが重要な気がしています。
webアプリを作るならjavascriptだけではなくHTML/CSSを知って、操作対象としているwebページがどうできているのかを理解する必要がありますし*1pythonが書けてTensorflowやchainerが使えても機械学習のプロになれるわけではないですし、JavaやKotlinが書けるだけでAndroidアプリが作れるわけではなくAndroidアプリの構成とかOSの特性とかを合わせて理解する必要があるわけです。

プログラミングは手段であって目的ではないので、やはり目的意識って大事ですね。書きながら自分に言い聞かせています。

*1:まあさすがにこれは当たり前すぎていい例ではないか

ARCoreでGoogleCloudVisionAPI使って結果表示するアプリ作った

スマホカメラで撮影した画像をGCPのCloudVisionAPIに送って物体認識し、結果をAR表示するアプリを作りました。

テキストを平面的に表示しているだけなのでARっぽさが出ていないですが…
表示はもう少し工夫したほうが面白そうですね。

github.com

f:id:fuzzy0:20190103012327j:plainf:id:fuzzy0:20190103012332j:plain
GCP CloudVisionAPIの結果をAR表示

処理の流れ

  1. ARCoreでカメラ画像を取得する
    地味に一番苦労しました。苦労した記録はこちら。
    qiita.com
  2. 画面タップを検出し、画像をbase64エンコードしてGCPのCloudVisionAPIに送信する
    string System.Convert.ToBase64String(byte[])base64エンコードします。
  3. jsonの応答を受け取り、3Dオブジェクトとして表示する
    表示位置は固定値でカメラの前方〇cmのように設定しています。
    jsonからC#インスタンスにデシリアライズする方法は下記記事を参考にしました。
    qiita.com

参考にしたコードはARCoreのExampleの、HelloARとComputerVisionです。

python使い始めて1年半経ったので好き嫌いをまとめてみる

python使い始めて1年半経ちました。(python3です)
機械学習関連に加え、ちょっとした作業のためのツールとして使ったり、趣味でwebバックエンドとして使ったりしました。

現時点で感じているpythonの好き嫌いをまとめてみます。
(それほど多くの言語のことを知っているわけではないので、これから意見が変わることは大いにありそうです。)

pythonの好きなところ

pythonに限ったことではない要素が多いかもですね。。

とにかく読みやすい

pythonの最大の特徴であるインデントによるコードブロックにより無駄な行がなくコンパクトになることをはじめ、 細かな記法が基本的にシンプルに設計されている印象を受けました。

読みやすさを重視したpythonの最大の利点だと思います。教育用に薦められるのも頷けます。

リストのインデクシング

  • リストに対する添え字が[開始:終了:間隔]と指定できる
  • マイナス値で末尾からの数を指定できる

ので、スライスやリバースが簡単。

s = "hello world!"
print(s[-2]) # d
print(s[::-1]) # !dlrow olleh

swapの書き方、比較の書き方

C言語から来たのでうれしい仕様でした。

# swap
a, b = 0, 1
a, b = b, a # a: 1, b: 0

# 比較
0 < a < 10 # True

for-else

for文内でif文で判定し、breakで処理を中断するケースは多々あります。
この時、一度もbreakに引っかからなかったとき「だけ」行いたい処理を書くとき、elseが使えます。

これもC言語から来た私は感動しました。

def func(names):
    for s in names:
        if s.startswith("ぼ"):
            print(s)
            break
    else:
        print("ぼで始まるやつなんかいないよ!!")

func(["たかし", "あきら", "すぐる"]) # ぼで始まるやつなんかいないよ!!
func(["たかし", "あきら", "すぐる", "ぼく"]) # ぼく

リスト・辞書展開

関数にリストや辞書の各値を展開して渡すことができます。何かと便利です。

def func(num, msg):
    print(msg * num)

l = [3, "hello"]
d = { "num": 3, "msg": "hello" }
func(*l) # hellohellohello
func(**d) # hellohellohello

変数への代入ならカンマ区切りで展開できます。

l = [1, 10, 100]
a, b, c = l

リスト内包表記

リストに対する繰り返し処理を行い新たなリストを生成するコードをワンライナーで書かけます。

l = ["バッツ", "レナ", "ガラフ", "ファリス"]
count = [len(s) for s in l]
print(count) # [3, 2, 3, 4]

なお、辞書やジェネレータを作る内包表記もできます。

d = {s: len(s) for s in l} # {'バッツ': 3, 'レナ': 2, 'ガラフ': 3, 'ファリス': 4}
g = (len(s) for s in l)
next(g) # 3
next(g) # 2
next(g) # 3
next(g) # 4

デコレータ

python以外にはなさそうな機能で、デコレータというのがあります。
主に関数のラッパ関数を作るときのシンタックスシュガーとして使われ、Flask等のライブラリを使うとその良さがわかります。
(より正確には関数を引数に取る関数を書く際のシンタックスシュガーであり、工夫次第でいろいろできます。マーキングとか。)

Flask公式トップのサンプルコード

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

自分でコードを書くときに使う機会があるかというとほとんどないのですが、 ライブラリを使うときには結構よく出てきて、使いやすいので、pythonが好きな理由の一つになりました。

ジェネレータ

ジェネレータは、イテレータとして使える関数のようなイメージです。
returnではなくyieldで値を返すと、次にその関数を呼んだときに続きから実行してくれます。

def generator_sample(count):
    for i in range(count):
        yield f"hello, {i}!"

hello10 = generator_sample(10)
print(next(hello10)) # hello, 0!
print(next(hello10)) # hello, 1!

などに使えるイメージです。

ダックタイピング

以前は静的型付けの言語ばかりやっていたので、型宣言がないとかどうやってプログラム書くの?と思っていたのですが、 慣れてきたら逆に型宣言が鬱陶しくなってしまいました。(個人開発のレベルでは、ですが)

ダックタイピングとは、

"If it walks like a duck and quacks like a duck, it must be a duck"
(もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルである)
Wikipedia

で表現されるように、「このメソッド持ってるならもうそれってことでオッケー」っていう考え方で、 作っているプログラムの仕様を把握できている限り、非常に柔軟な書き方ができます。

オブジェクト指向ポリモーフィズムを超ラフにした感じでしょうか。

たぶん大規模開発の現場で多用すると、辛くなります。。

pythonの嫌いなところ

たった1年半しかpythonに触れていない初学者の意見ですので、 事実と違う、とか、これはこうすれば/こう考えればいい!とかあったらご指摘ください。

グローバルな組み込み関数がある

len(), max(), min(), sort(),,,

最初は、今時なんなの?と思いましたが慣れると普通に受け入れていて、でも一周回ってやっぱりなんなの?と思い始めました。
というのも、クラス定義するとき、グローバル関数に引数として入ったときの処理を書くにはアンダースコア付きのメソッド(特殊メソッド)を定義するので、 だったら最初からメソッド定義すればいいじゃん・・って思ったからです。

これ、何か深いpythonicな意味があるのかと思っていたら、どうやら過去の遺産みたいなんですよね。
デザインと歴史 FAQ — Python 3.6.5 ドキュメント

主な理由は歴史です。

そうですか。。。

と思ったら英語原文だとちょっと違う文章でした。

Design and History FAQ — Python 3.7.2 documentation

前置のほうが後置よりわかりやすいじゃん、っていうのと、メソッドより関数のほうが引数と戻り値の型が推測しやすいじゃん、ということのようですが、 要は好みの問題っぽいですね。
pythonが読みやすさを重視していること、数学系分野に強いこと、もともと変数に型を定義しない文化であること、を考えると、全うな意見なのかもしれません。

変数に型を強制する方法がない

型推論の言語でも、型を強制したい場面は結構あると思いますが、pythonはそれがありません。
3.5からtypingモジュールとして型ヒントが仕様に追加されましたが、コメントの拡張的な位置づけで、 実行時エラーになったりはしません。

pythonは強い型付けの言語なので、以下のように異なる型の変数で演算するとエラーにしてくれますので、 変数の定義後であればある程度安全ですが(とはいえ実行時エラーにしかなりませんが)、 関数の引数などは型チェックを毎回自前でするのもつらみがあります。

a = 3
b = "10"
print(a+b) # TypeError: unsupported operand type(s) for +: 'int' and 'str'

型の扱いに関しては発展途上のようで、静的型チェックツール(mypy)が開発されたり、 そもそも型チェックを入れることで開発速度が落ちる弊害もあるので一概に善とは言えない、など、 これからpythonとしてはどうなっていくか楽しみな部分です。

型ヒントとその周辺の話題について、以下の記事が参考になりました。

qiita.com

複数行(=文)を無名関数として定義する方法がない

無名関数といえばlambda式ですが、受け付けるのは「式」のみで、「文」は書けません*1

なぜこの仕様が嫌いかというと、pythonをツール的に使うとき、使い捨てコードとしてメソッドチェーンで処理を書きたいときがあって、 それが実現できないからです。

# やりたいことのイメージ(動かない)
some_func(filename).some_method(lambda x:
    # 何らかの処理
    # 何らかの処理
    # 何らかの処理
).some_method(lambda x, y:
    # 何らかの処理
    # 何らかの処理
    # 何らかの処理
)

javascriptとかでは頻繁にみる形式ですが、pythonではコードブロックがインデントであることも相まっていい具合に書く方法がありません。

やはりdefで別途定義して引数に入れるか、デコレータを駆使して何かするか、ということになると思います。 The Zen of Python からしても、上記の形式はきっと「読みにくい」「複数通りの書き方が生まれてしまう」ってことになるんだと思います。

その他、pythonについて知ったこと

好きでも嫌いでもなく、知ったことについてもまとめておきます。

処理が遅い?

競技プログラミングとかしない限り実感するほど遅くはならないと思いますが、やっぱり遅いには遅いです。

本当に速さが必要ならCで書かれたライブラリ(numpy等々)使うか、自分でCで書いて作るのがいいようです。
Cと親和性が高いのはpythonのいいところかと思います。

ちなみに、実行時にバイナリコンパイルされたpycファイルが作られるので、何かしら最適化できるのかと思ったら、現状は処理速度にはほとんど寄与しないようです。

1. Command line and environment — Python 3.7.2 documentation

-O
Remove assert statements and any code conditional on the value of __debug__. Augment the filename for compiled (bytecode) files by adding .opt-1 before the .pyc extension (see PEP 488). See also PYTHONOPTIMIZE.

-OO  
Do -O and also discard docstrings. Augment the filename for compiled (bytecode) files by adding .opt-2 before the .pyc extension (see PEP 488).

おわりに

pythonはどちらかというと好きですが、もうちょっと遊び要素というか、柔軟性も欲しいなって思うことがあります。
Rubyとかは遊び心満載だと聞きますし、かじってみたい気もします。
最近flutterで話題再燃しているDartも、サンプルコードを見るとしっくりくる感じなので、気になっています。

来年はまた一つなにか言語習得したいです。

読書メモ 「これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほん」

これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほんを読んで

HTML, CSS, JavaScriptの基本から、レスポンシブ, JQuery, Ajax, SPAフレームワーク(Vue.js)まで、基本的なことが幅広く丁寧に説明されているので、フロントエンドの要素技術の全体像と成り立ちを知るにはちょうどよい良書でした。

自分としては以下のような成果がありました。

1つのアプリを作るうえでどのような流れでデザインしていけばよいかがわかった

  1. HTMLで必要な要素を並べる
  2. CSSのレイアウト調整に必要な単位にdiv, spanなどで要素をまとめる
  3. CSSでレイアウトを整える
  4. JavaScriptで動きをつける

本書ではフォーム画面を例に、この流れに沿ってデザインを整えていくので、理解しやすかったです。
実際の現場でこういう流れになるのかはわかりませんが。。

自分がCSSにかなり疎いことがわかった

Webデザインには必須のCSSですが、なんとなく「CSS=デザイナ向け」というイメージがあって、Webアプリにはそこまで必要ない、適宜bootstrapとか使えばほぼ知らなくてもいける、とか思っていました。
しかし、もちろん細かい知識は要らないかもしれませんが、この本で説明されているレベルの基本事項は必須知識でした。
プログラムから操作する対象をまとめるのによくdiv, spanを使うわけですが、それらのレイアウトを調整するのにCSSが必須だからですね。

div, spanの使いどころが悪いと、CSSセレクタでの指定の仕方がぐちゃぐちゃになったりするので、CSSで操作すべき範囲をよくイメージしてHTML構造を作るのが大事だと思いました。
CSSノーマライズ/リセットの概念、@import、CSSプリプロセッサ、もこの本で初めて知りました。

まあbootstrapなどのCSSフレームワークを使えばそれほど知らなくてもできるのは正しいかもしれないのですが、そもそも基礎知識がないと、フレームワークの使いどころがわからないレベルでした。

JQueryから最近のSPAフレームワークへの成り立ちが理解できた

素のJavaScriptにおける「DOMエレメントの指定の煩雑さ」をJQueryが解決し、JQueryにおける「DOMツリー構築の煩雑さ」を最近のSPAフレームワークが解決している、ということでした。
(細かいことを言えば、コンポーネント化とか、もっともっといろいろな要素があるのだろうと思いますが、まだ初心者なのでよくわかっていません)

JQueryや各フレームワークを学ぶ際に意識するポイントがわかった気がします。もっと学んでいきたいと思います。

JQueryとVue.jsで同じことをするアプリを書いてみた

github.com

Qiitaの投稿を検索してタイトルを表示するだけ。
JQueryからVue.jsになるとHTMLタグにidをつけなくてもいいことや、JavaScript側ではHTML構造を意識する必要がないあたりに、特に書きやすさの差を感じました。

githubにリポジトリ作った後のローカルとの同期手順のメモ

  1. ローカルで初期化
    git init
  2. ローカルで開発し、適宜コミット
  3. GitHubリポジトリ作成。ReadmeやLICENSEも作る
  4. ローカルでリモート設定追加
    git remote add origin git@github.com:<user name>/<repo name>.git
    git remote -v
  5. いったんリモートからPULL git pull
  6. リモートにPUSH…するとエラーになるので、MERGEで対処
    git merge --allow-unrelated-histories origin/master
  7. ローカルの分をPUSH
    git push origin master

参考:
githubリポジトリ作成後の初プッシュでちょっとハマったこと - Qiita
初めてGitHubリポジトリにpushしたらrejectedエラーになったときの対応メモ - Qiita