プログラマ行進曲第二章

主にソフトウェア関連の技術をネタにした記事を執筆するためのブログ

何度目か分からないiOSプログラミングへの再入門をまた始めたという話

前回の記事で、前職の同僚にiOSプログラミングを教え始めたという話をしました。

takuan-osho.hatenablog.com

今のところゆるゆると続いていて、私もiOSプログラミングはそこまで深くやったことはないので、教えるついでに自分も再入門しなおし始めました。

以前にもこのブログで何回か言及した記憶はあるのですが、私、iOSプログラミングに入門しては挫折するということを繰り返していて、「今だと10回は超えないが、両手で数えるくらいは入門しては挫折している」という状態です。

今度の再入門がどれくらい続くかは不透明ですが、仕事とは全く関係ない分野だからこそ飽きが来にくいということと、今回は前職の同僚と一緒に勉強しているということもあり、以前よりかは続けられるのではないかと目論んでいます。

前職の同僚に教える際に教材として使っている書籍はこちらです。

本気ではじめるiPhoneアプリ作り Xcode 10.x対応 (Informatics&IDEA)

本気ではじめるiPhoneアプリ作り Xcode 10.x対応 (Informatics&IDEA)

以前iOSプログラミングに入門したときに使っていた書籍の最新バージョンです。

前に使った時に分かりやすいと思ったことと、応用を見据えた事項を抜き出して構成している書籍だったので好印象だったことから選びました。特にWeb APIを利用したアプリ作りを入れているのが好印象でした。

他人にプログラミングを教えていると「ここで詰まると思っていたのに、別のこの場所の方が分かりづらくて詰まるものなのか」とか意外な発見があって、自分も勉強になってます。

次回はこの教えた経験をもとに、(iOS)プログラミング初心者が詰まった事項をコードを交えて少し紹介する記事を書ければいいなと思ってます。

前職の同僚にプログラミングを教えたという話

大したことではないんですが、少しでもいいから記録を残しておいた方が後々振り返ったりしたくなったときに有益だと思ったので記事の形にして残します。

ふと自分のiPhoneのTwitterクライアントの通知が来ていたのに気づき、アプリを立ち上げて何の通知か確認すると、DMが1通来ていることに気づきました。

ここ最近は普段DMでやり取りする相手もいないので「一体何だろう?」と思い、確認してみると前職の同僚から「Swiftの経験ありますか?もしよければ教えて欲しいです」(意訳)とメッセージが。

正直SwiftはiOSプログラミングに入門した際に必要な分だけしかやったことがなくて、人に教えられる程度のものが備わっているわけではないとは知りつつも、その同僚がどんなことを考えているか何回かやり取りした後、詳しいことを確認するために一回会って話すことにしました。

話しを聞いた人たちの了解を取ってこの記事を書いているわけではないので、機微な情報には触れない程度にザックリとしたことを書くと、以下のようなことが決まりました。

  • iOSプログラミングを始めようと思っている前職の同僚たち*1は各自集まりながら勉強していく
  • 私はアドバイザー的な形でその学習を補佐し、ベストエフォートでサポートする

一回みんなでモブプログラミングみたいなことをして、初めて触れるSwiftがどんなものかを体験するくらいのところまではいけました。

プログラミングを仕事以外で真面目に教えるという経験は中々得られないので、そこが自分にとって魅力的に感じ、まず一回試してみたのですが、結構楽しくてよかったですね。

今後続くかどうかは分かりませんが、可能ならユルユルと続いてもらえるといいなー、なんて思う週末でした。

*1:メッセージを送ってきたのは1人でしたが、話をしたのは複数名でした

macOS MojaveにしてからpyenvでPythonをインストールしようとしたらzlib周りでエラーが出てインストールできなくなったのに対処した

pyenv公式にissueが立っていました。以上。で終わる話ですね。

github.com

macOS SDK headerがないせいでエラーになるらしく、以下のようにすればいいとのこと。

xcode-select --install
sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /

pyenvを使うな? そうですね。はい。

コードからPythonパッケージ名を取得する方法が分からなかったので質問した話

この3連休でSphinxの開発合宿に参加しています。

sphinxjp.connpass.com

その時の作業で「Pythonパッケージ名を取得するコードの書き方」が分からなくなり、その場で質問した時に色々教えてもらったので、軽めにメモを取って記事にすることにしました。

一番素直に(愚直に?)やるのは、以下のように __file__ を利用する方法とのことでした。

# in <package>/__init__.py:

package_dir = os.path.abspath(os.path.dirname(__file__))

コードを見れば「ああ、そうですね。そう書けば取れそう」と分かるものですが、普段Pythonを書かなくなってしばらく経っていたこともあってか、どう書けばいいのか分からなくなっていたので助かりました。

この書き方を使って、以下PRの実装に役立てています。

github.com

ちょいテクとして記録を残しておいて、また忘れたときにブログから引っ張れるようにしておいて安心して忘れられるようにしたいと思います。

他にパッケージ名を取得するやり方としてsetuptoolsのpkg_resourcesを使うという方法もあると聞きました。ただ、こちらは詳しいやり方を聞いたわけではなく、詳しく調べる余裕も無いので、教えてもらったリンクだけ貼ってお茶を濁しておきます。

Package Discovery and Resource Access using pkg_resources — setuptools 40.6.3 documentation

redisのコマンドが失敗した時にfailするようにするansibleのtaskを作る

仕事で直面したちょっとしたtipsを掘り起こしてブログにする形式の記事です。

プロダクトでredashを使っていて、その関係でAWSのElastiCache(redis)を使っているのですが、redashの内部で使われているCeleryがCPUを食い潰すくらい暴走することがあったりして時折再起動する必要があり、再起動した後redisをflushdbする必要があるのですが、その際に直面した問題がありました。

どういう問題かというと、redisをflushdbしたとき、成功しようが失敗しようがexit codeが0になってしまい、ansibleのtaskでredis flushdbしたときにそのままでは失敗した時にfailして落ちるという動作にならないということです。

細かい検証をしたわけでは無く、仕事でやったときはredis-cliではなくncコマンドを利用してflushdbするようにしていたので、全般的にそうなのか分かりませんが、今手元のPCで軽く確認した限りではerrorと出るようなコマンドをredis-cliで実行してもexit codeが0のままでした。

$ redis-cli flushdb
OK
$ echo $?
0

$ redis-cli flushdb -n 0
(error) ERR syntax error
$ echo $?
0

単にコマンドをマニュアルで叩く形式なら出力結果を目で確認し、失敗したら再度実行すればいいのですが、今回は長いansibleのplaybookの中にある一つのansibleのtaskとして利用したかったので、flushdbが失敗したらその場でansibleが失敗するようにしたかったのです。

失敗を検知したかったといっても、失敗した時にもexit codeが0が返ってくる状況でどうやればいいのか分からなかったのですが、検索して見たらredisの公式ドキュメントに解決の糸口になる情報が書かれていました。

https://redis.io/topics/protocol#resp-errors

RESP has a specific data type for errors. Actually errors are exactly like RESP Simple Strings, but the first character is a minus '-' character instead of a plus. The real difference between Simple Strings and Errors in RESP is that errors are treated by clients as exceptions, and the string that composes the Error type is the error message itself. The basic format is:

"-Error message\r\n"

要するに、コマンドが失敗したら、返ってくるエラーの頭の文字が - になるということです。

これを利用して、以下のようにansibleのfailモジュールを組み合わせれば、redisのコマンドが失敗した時にansibleがfailするtaskを実装できます。

以下のコマンドは実際に仕事で書いたansibleのtaskで、面倒なので行頭の空白は調整してないです。

       - name: Execute redis flushdb
         shell: <省略>
         register: redis_command_result

       - fail:
           # The first character of redis RESP Errors is minus '-' character.
           # See https://redis.io/topics/protocol#resp-errors
           msg: "Fail because redis flushdb failed."
         with_items: "{{ redis_command_result.stdout_lines }}"
         when: item|first == "-"

jinja2のfilterのfirstを利用して、返ってくるエラー文字列の各行の頭に - が存在したときはfailするというようにして解決しました。

マニュアルで実行するときは特に問題ならないことがansible経由だと問題になることが多々あって面倒ですね。

2018年の振り返り

昨年も年末に振り返りをしたので、今年もします。

takuan-osho.hatenablog.com

以前のものはこちら。

takuan-osho.hatenablog.com

takuan-osho.hatenablog.com

takuan-osho.hatenablog.com

成果確認

takuan-osho.hatenablog.com

振り返るまでもなく、全て中途半端になっていることは分かっていますが、振り返ります。

IT系技能関連の目標

[UI|UX|Web]デザインを勉強して、自分でプロトタイプを作れるようにする

こちらに関しては計測可能な目標として以下の4つを挙げていました。

  • 参考となるWebサイトを選び、そのWebデザインをAdobe XDなどで模写する
  • 自作のアプリのプロトタイプをAdobe XDなどで作成する
  • カスタマージャーニーマップなど、UXデザインをする際に行う一連の流れを自分で一通り体験する
  • 自分自身のポートフォリオサイトを立ち上げる

これに沿って自分が達成できたかどうか考えると、×としか言いようがないですね。

自作アプリのプロトタイプをAdobe XDで作ろうとしていてまだプロトタイプはできてないですし、Adobe XDで模写するのも途中で終わっていて、取りかかり始めてはいましたが、一つとして終わってないので、まあ無理ですねえというところです。

ITはあまり関係ない目標

1年で12冊は本を読み、感想ブログを書く

これも×ですね。一応3冊は読んだ記録を残していますが。

takuan-osho.hatenablog.com

takuan-osho.hatenablog.com

takuan-osho.hatenablog.com

年始めはいいスタートが切れたのですが、その後5月くらいになってから書籍を読む余裕がなくなっていったのと、読んでもブログに書いてないのが重なって、とても12冊は読めてないからです。

もう少しハードルを下げて来年も同様の抱負を立てて挑戦したいです。

(骨盤が後傾せずに)開脚ができるくらいの柔軟性を得る

これに関しては△をあげていいのかなと思います。

以前書いたように左脚内部の筋が痛くなりやすいのは変わってなく、開脚の角度も90度いくかどうかという固さではあるのですが、以前より骨盤が後傾せずに身体を前に倒せる回数が増えてきたので、△くらいはあげてもいいかなという状況になりました。

まあ当然まだまだなので、何かしら日常的に組み込めるような柔軟性向上の仕組みを考えて実践することがそろそろ必要だと思っています。

まとめ

今年は7月と10月に手術をする羽目になって、7月〜11月の4ヶ月間はQoLがダダ下がりな状態で過ごしていて、あまりいい年とは言えなかったのが辛いといえば辛かったです。

何の手術をしてどこら辺が大変だったかというのをブログにまとめて記事にしようかと思っていたら大晦日になってしまったので、来年頭のまだ休みの期間中に書いてアップするようにできればと思っています。

来年はもっとハードルを下げて3つくらいの抱負を立てて、1年を有意義に過ごせるようにしたいです。

jqコマンドのAlternative operatorを初めて知って使った

仕事で必要があって「あるAWSアカウントで使っているRDS for PostgreSQLのバージョン、リソース名などの設定を全リージョン分表示する」ということをしたくて、 jqコマンドを使って色々加工する必要があった時使ったやり方についてメモします。

リージョン毎の区切りとして空行を入れたかったのですが、jqコマンドについて詳しくないこともあり、以下のようなコマンドをxargsと組み合わせてそのまま使ってしまうと、リソース毎の表示に空行がないままで表示されてしまい、各種設定の値がどのリージョンのどのリソースのものなのか分かりづらくなってしまってどうしたらいいのか悩んでいました。

aws rds describe-db-instances | jq .DBInstanceIdentifier,.DBInstanceArn,.EngineVersion,.AutoMinorVersionUpgrade

AutoMinorVersionUpgrade の後に空行を入れられるようにできればいいのですが、jqコマンド直下の箇所なのでechoを入れるわけにもいかず、「jqコマンドに条件分岐に使える式があるかもしれない」と探したところ、StackOverflowか何かでjqコマンドにAlternative Operatorなるものがあることを知りました。

https://stedolan.github.io/jq/manual/#Alternativeoperator://

A filter of the form a // b produces the same results as a, if a produces results other than false and null. Otherwise, a // b produces the same results as b.

これを使ってxargsと組み合わせて、以下のようにコマンドを作り実行して、区切りを空行にして見やすく表示できました*1

$ cat region-rds.txt
us-east-2
us-east-1
us-west-1
us-west-2
ap-south-1
ap-northeast-2
ap-southeast-1
ap-southeast-2
ap-northeast-1
ca-central-1
eu-central-1
eu-west-1
eu-west-2
eu-west-3
eu-north-1
sa-east-1

$ profile=sample
$ cat region-rds.txt | xargs -I{} sh -c "echo [{}]; aws --profile $profile --region {} rds describe-db-instances | jq '.DBInstances[] | select(.Engine == \"postgres\")' | jq -r '.DBInstanceIdentifier,.DBInstanceArn,.EngineVersion,.AutoMinorVersionUpgrade,.Null // \" \"'; echo"
[us-east-2]

[us-east-1]

[us-west-1]

[us-west-2]

[ap-south-1]

[ap-northeast-2]

[ap-southeast-1]

[ap-southeast-2]

[ap-northeast-1]
dev-db-postgresql-1
arn:aws:rds:ap-northeast-1:0001111:db:dev-db-postgresql-2
10.x.x
true

dev-db-postgresql-2
arn:aws:rds:ap-northeast-1:0001111:db:dev-db-postgresql-2
10.x.x
true


[ca-central-1]

[eu-central-1]

[eu-west-1]

[eu-west-2]

[eu-west-3]

[eu-north-1]

[sa-east-1]

実行しているコマンドが長すぎるのはひとえに私のシェル芸能力が低いからですね。

.Null // \" \" で使っている // がAlternative Operatorで、この場合はawscliから帰ってくるjsonのキーに Null なんてものはない(はず)という性質を利用して、本来 null と帰ってくるところを と、空白を返すようにして、区切りとして空行っぽくなるようにしています。

恐らくシェル芸できる力がある人はもっと別のやり方でスマートにできるのかもしれませんし、Alternative Operatorをそんなに使う機会があるとは思えませんが、一つのやり方として知っておいていいのかもしれないとメモしておきます。

*1:少なくとも自分には見やすくできたかと