本『リーダブルコード』の感想
リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)
- 作者:Dustin Boswell,Trevor Foucher
- 発売日: 2012/06/23
- メディア: 単行本(ソフトカバー)
原題は
The Art of Readable Code: Simple and Practical Techniques for Writing Better Code
である。
邦題では「リーダブルコード」であるが、原題では「The Art of Readable Codes」なので本来は Art の意味もタイトルに含まれている。
その言葉の意味を考えると、これは内容的には、コーディングに関しての Art, 芸術に関する本である。
基本的なところだと、たとえば命名や改行の仕方で、そのコードの読みやすさというは変わる。(命名が適切であり、役割を簡潔に示せているか? 改行された位置により処理が一つのブロックであることを示せているか?)
残されたコードが読みやすく、理解しやすく、あとで読む人(それはすっかりコーディングした当時のことを忘れた自分かもしれない)がストレスなく開発できるかどうか?
そういったコードを通した情報伝達の精度をいかによくするか、という芸術だ。
逆に、この情報伝達がうまくできていないと、コードというダンジョンを、頼りない松明片手に探索する考古学をしなければならない。 (そして運が悪ければダンジョンから出れずに、壁に「yyyy/MM/dd 私は解析に失敗した。ここに眠る ◯◯」とコメントする羽目になる)
本は 200 ページくらいで読みやすい。
「こうしたらコードが読みやすくなる(Readable)」という tips は、自分でコーディングしたり、ほかの人のコードを読んだりして無意識に獲得していくものも多いが (本を読んで、これはやっているなぁ、、という部分もある)、文書にして明文化したことにより、それらが共通知識として残るので価値がある。
個人的には範囲を示すときに start/stop は包括的で、begin/end は終端が排他的なものに使うというのが、なるほどなあ、と思った。
たとえば
2020/01/01 の1日を範囲としたい場合
- start 2020/01/01 00:00:00
- stop 2020/01/01 23:59:59
ではなく
- begin 2020/01/01 00:00:00
- end 2020/01/02 00:00:00
とできるし、後者の方が自然である。
前者だと厳密に1日の終わりを示すことは難しい。なぜなら 59 秒は1日の終わりでなく、まだ1秒あるからだ。(さらに 999... とミリ秒単位の指定を続けると精度はあげることはできるが、、)
AppStoreConnect での米国輸出規制の暗号に関する質問をスキップする
免除される暗号のみを使用しているのに App Store Connect でアップロードごとに毎回、暗号に関する質問を答えるのが面倒。
その場合は、
Info.plist に以下を追加する。
<key>ITSAppUsesNonExemptEncryption</key> <false/>
これでアプリには免除されていない暗号を使用していない、とマークされるので暗号に関する質問をスキップできる。
(もし、true にした場合はこの逆で、免除されていない暗号を"使用している"、とマークされる)
そもそもなぜアプリを公開する時に、暗号に関する確認があるのか?
暗号利用環境に関する動向調査(独立行政法人 情報処理推進機構)
アメリカに限らずに「暗号」というは、国家の安全保障・戦略にかかわるものなので、その技術は国外に出て(輸出)は困る、ということらしい。(もちろん、普及している標準的な暗号技術はその対象にはならない)
そして、AppStore のアプリはアメリカからの配信(輸出)になるので、米国輸出管理法の規制の対象になる、ということみたい。
iOS 14 の App Clips について
iOS 14 の App Clips に関して調べたことのまとめ
資料一覧
- Introducing App Clips
- Human Interface Guidelines / App Clips
- Developer Document / App Clips
- Creating an App Clip
- Developing a Great App Clip
資料から重要そうなところを抜粋
概要
(画像は Apple のもの)
App Clips とはアプリ全体をダウンロードしなくても、ユーザがアプリの必要な機能だけをすばやく取得し、使用できる仕組み。
アプリが、ユーザに「瞬間的なエクスペリエンスを提供」する場合は App Clips の採用を検討する。
たとえばコーヒーショップアプリが AppStore にあるとすると、ユーザはそのアプリを使ってドリンクを注文したり、お気に入りのドリンクを保存したり、クーポンを収集したり、特別オファーを取得したりできる。
対照的に、App Clips はドリンクを注文する機能のみを提供する。ユーザがコーヒーショップを通り過ぎると、システムは Siri からの位置ベースの提案をデバイスに表示する。
ユーザーは提案をタップし、システム提供の App Clips カード(上記の図の中央で示されている)で App Clips を起動し、すぐにドリンクを注文できる。
ユーザはどこから App Clips を見つけて起動できるか?
https://developer.apple.com/documentation/app_clips/developing_a_great_app_clip
ユーザが App Clips を見つけて、起動する方法は以下がある。
- 物理的な場所での NFC タグまたはビジュアルコードのスキャン
- Siri から場所ベースの候補をタップする
- Map アプリでリンクをタップする
- Webサイトでスマートアプリバナーをタップする
- メッセージアプリで誰かが共有したリンクをタップする
App Clip Codes
https://developer.apple.com/app-clips/
App Clips にアクセスするためのビジュアルコード。
見た目も美しく、はっきりしている、ユーザが App Clips を見つけるための最良の方法となる。
この App Clips のコードを作成するツールは 2020年後半に提供される予定。
優れた App Clips の設計
- 必要な機能だけ。ユーザが目の前のタスクを処理することに集中できるように機能は限定する。
- App Clips のみで価値があり、タスクを完結できるようにする。App Clips をサービスの宣伝に使用しないように。
- わかりやすく、直線的にタスクを実行できるようにインターフェースを提供する。App Clips にはタブバー、複雑なナビゲーション、設定は含めることはできない。目の前のタスクを簡潔なインターフェースでユーザが実行できるようにする。
- 小さいほど良い。小さいほどユーザはすばやくダウンロードでき、実行できる。できるかぎり不要なアセット、コードを削除する。
- Apple Pay のサポートを検討する。支払い情報の入力は、長くて間違いが起こりやすい作業のため Apple Pay が使用できると良い。
- アカウント作成を要求しない。ユーザがすぐタスクを完了できるように、アカウント作成はタスク完了後にユーザに促す。
- App Clips からアプリの移行をスムーズにする。アプリ全体をダウンロードすると、以前の App Clips はアプリに置き換えられる。ユーザが App Clips を使用していた時のエクスペリエンスをアプリでも提供する。
App Clips のライフサイクル
https://developer.apple.com/documentation/app_clips#overview
- ユーザがアプリをインストールしない場合、システムは一定期間操作がないと、 App Clips を自動的に削除する。
- ユーザが App Clips に対応するアプリをインストールすると、 App Clips がアプリに置き換わる。
App Clips の開発
https://developer.apple.com/documentation/app_clips/creating_an_app_clip
アプリのプロジェクトに App Clips のターゲットを追加する。
App Clips の信頼性の検証をするために Web サーバ構築も必要になる。
考察
以下、個人的な考察。
- App Clips は一定期間操作されないと、システムにより削除される。
- この期間が不明だが、App Clips を気にいって繰り返し使うユーザは、App Clips の入手の手間を嫌って、どこかのタイミングで AppStore から完全なアプリを入手することなりそう。
- App Clips で良い体験をユーザが感じれば、アプリ本体のダウンロードに繋がる。
- 開発時点で機能が分離できていないコードでは、App Clips 用に機能提供することのコストが大きくなるため、プロジェクトは疎結合の状態が望ましい。
iOS / Android 用のローカライズ文字列ファイルを生成するツール「strgen」
iOS / Android のローカライズ文字列ファイルを一括で生成するツールstrgen(Python)を作った。
PyPI に登録してあるので、 pip でインストールできます。
概要
多言語情報を記載した CSV と、設定を記載した YAML ファイルを入力として、以下のファイルを出力する。
- iOS 用ファイル
- 各言語用の
Localized.strings
- ローカライズのキーが定義されている Swift ファイル(
LocalizedStrings.swift
)
- 各言語用の
- Android 用ファイル
- 各言語用の
strings.xml
- 各言語用の
strgen を使うメリット
一元管理できる
iOS / Android のローカライズファイルのソースが、単一の CSV になり、多言語が一元管理できる。
多言語更新のミスが発生しにくい
ツールで生成したファイルをプロジェクトに反映させるだけなので、ファイル(Localized.strings, strings.xml)を直接編集するのに比べ、ミスが発生しにくい。
iOS のローカライズの効率がよくなる
hello
というキーでローカライズ文字列が存在する場合、 iOS はキーを文字列で指定してローカライズ文字列を得るので、以下のようになる。
NSLocalizedString("hello", comment: "")
しかし、これは存在していないキーも指定できる問題がある。
たとえば、以下のようにキー指定をミスした場合、ビルド時には分からず、ミスがわかるのは実行時に確認した時だ(ローカライズ文字列が正しく表示されないので)
NSLocalizedString("hellow", comment: "")
この問題の対応として strgen は iOS の多言語ファイルを生成する時に、一緒にキーを列挙した swift ファイル(LocalizedStrings.swit)も作成する。
import Foundation class LocalizableStrings { enum Key: String { case hello = "hello" } }
この swift ファイルからキー定義を参照するようにすると、ローカライズのコーディングの際に、ビルド時点でミスに気付けるので、効率がよくなる。
NSLocalizedString(LocalizableStrings.Key.hello.rawValue, comment: "")
strgen を試してみる
サンプルで動作を確認できます。
インストール
まず、 pip で strgen をインストールします。
$ pip install strgen
これで、コマンドラインから strgen を実行できるようになる。
$ which strgen
/usr/local/bin/strgen
サンプルを動作させてみる
- プロジェクトを clone します。
$ git clone https://github.com/daisuke-t-jp/strgen
- カレントディレクトリを clone したプロジェクト内の
strgen/sample
フォルダに変更します。 - 以下のコマンドを実行。
$ strgen strgen.yml
build
フォルダを確認します。
使い方
そのほかの使い方、YAML ファイルの仕様などは、README を参照してください。
Python パッケージ作成に関する情報まとめ
Python パッケージ作成、PyPI(パイ・ピーアイ) への登録などに役立つ情報を、まとめる。
setup.py
だけ使用するパターン、setup.cfg
も使用するパターン、__init__.py
に多くの役割を持たせるパターン/ほとんど役割を持たせないパターン、などパッケージ作成に関してさまざま選択肢があるので、いろいろな例を見ておくと良い。
関連公式ドキュメント
- Python モジュールの配布 — Python 3.9.1rc1 ドキュメント
- 2. setup スクリプトを書く — Python 3.9.1rc1 ドキュメント
- 6. モジュール — Python 3.9.1rc1 ドキュメント
参考情報
- Python Packaging User Guide — Python Packaging User Guide ドキュメント
- 【Techの道も一歩から】第21回「setup.pyを書いてpipでインストール可能にしよう」 - Sansan Builders Blog
- PythonのCLIパッケージの作り方 - karakaram-blog
- Pythonのパッケージ周りのベストプラクティスを理解する - エムスリーテックブログ
- setuptools: Pythonパッケージ作成 - Heavy Watal
- Pythonのパッケージングのベストプラクティスについて考える2018 - 朝日ネット 技術者ブログ
- Pythonでグローバルコマンドを含んだパッケージを作る - Qiita
- 自作のPythonパッケージをPyPIに登録してpip install可能にする - Qiita
参考になる Python パッケージ(OSS)
- GitHub - VaasuDevanS/cowsay-python: The famous cowsay 🐮 for GNU/Linux is now available for python 🐍
- 非常にシンプルなパッケージ(CLI の参考にもなる)
- GitHub - pypa/twine: Utilities for interacting with PyPI
config.cfg
の書き方が参考になる(CLI の参考にもなる)
- GitHub - jazzband/django-redis: Full featured redis cache backend for Django.
- GitHub - yaml/pyyaml: Canonical source repository for PyYAML
パッケージのインストールテスト
パッケージを作ったらインストールして試してみる
開発用
開発中のパッケージは、こちらの方法でインストールしてテストする。
$ python setup.py develop # もしくは $ pip install -e .
配布用
# 配布用パッケージの作成 # これで dist/ 以下にパッケージ(tar.gz)ができる $ python setup.py sdist # 配布用パッケージのインストール $ pip install dist/*
パッケージ情報の確認
$ pip show <パッケージ名>
アンインストール
$ pip uninstall <パッケージ名>
PyPI への登録
登録するためのツール twine
が入っていないならインストールする。
$ pip install twine
登録。
$ twine upload --repository pypi dist/*
iOS でパラパラ漫画のような見た目のインジケーターを作った
everysing というカラオケのアプリで、読み込み中に表示されるインジケーターがパラパラ漫画のようになっていて、キュートな感じがしてよい。(マイクやヘッドフォンのアイコンが表示される)
この UI を再現したく、パラパラとアニメするインジケータを作ってみた。
↓こんな感じに画像を設定すれば、パラパラアニメで表示される。
import ParaParaIndicator class ViewController: UIViewController { let paraparaIndicator = ParaParaIndicator() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. // Images for flipping paraparaIndicator.images = [ UIImage(named: "camel")!.withRenderingMode(.alwaysTemplate), UIImage(named: "deer")!.withRenderingMode(.alwaysTemplate), UIImage(named: "elephant")!.withRenderingMode(.alwaysTemplate), UIImage(named: "giraffe")!.withRenderingMode(.alwaysTemplate), UIImage(named: "kangaroo")!.withRenderingMode(.alwaysTemplate), UIImage(named: "mouse")!.withRenderingMode(.alwaysTemplate), UIImage(named: "rhino")!.withRenderingMode(.alwaysTemplate), ] // Indicator frame paraparaIndicator.frame.size.width = 100 paraparaIndicator.frame.size.height = 100 paraparaIndicator.center = self.view.center // Tint color paraparaIndicator.tintColor = .cyan // Flip interval paraparaIndicator.timeInterval = 0.3 // Hide when stopped paraparaIndicator.hidesWhenStopped = true // Start animation paraparaIndicator.startAnimating() // Stop animation // paraparaIndicator.stopAnimating() self.view.addSubview(paraparaIndicator) } }
なお UIActivityIndicatorView
Like で扱えるように、以下のメソッドを実装し、インターフェースを似せてある。
- hideWhenStopped
- isAnimating
- startAnimating
- stopAnimating
macOS 10.15 から有効な EndpointSecurity API(SystemExtension.framework)
https://developer.apple.com/jp/system-extensions/
macOS 10.15 から、従来のカーネル拡張(KEXT)を使わずに、ユーザーランドで動作するソフトでシステムイベントを監視(おそらくイベントの許可/禁止も)できるようになった。
https://developer.apple.com/contact/request/system-extension/
まず Apple に SystemExtension.framework / EndpointSecurity API の使用リクエストを出し、許可される必要がある。
https://developer.apple.com/documentation/endpointsecurity
プロジェクトで Endpoint Security API を使用するには、以下の2つをリンクする。
- SystemExtension.framwork
- libEndpointSecurity.tdb
entitlements に com.apple.developer.endpoint-security.client = YES を設定する。
※Apple に API リクエストが許可されていないと、アプリがただしく起動しない。
従来の KEXT を使用してシステム監視(アンチウィルスソフトなど)する場合より SystemExtension.framework を使用するメリット
- Kernel extension で機能を実現した場合、ソフトはカーネルランドで実行されるため、ソフトの処理が遅いと OS 全体も遅くなってしまうなど OS の安定性に関わる現象が起きる。その分、実装もシビアになる。
- ユーザランド実行になるとここが、そこまでシビアではなくなる?
- Kernel extension 由来のセキュリティ問題がある場合、カーネル空間でその問題は発生するので OS デベロッパ(Apple)、ソフトデベロッパの責務の線引きが不明瞭になる。
不明な点
https://developer.apple.com/documentation/endpointsecurity/client?language=objc