Agile Tech EXPO(あじゃてく)に参加した
ちょっと前の2020/10/3に開催されたAgile Tech EXPO(あじゃてく)に参加した。その日は生憎休日出勤となり、あまり積極的には参加できなかったがとてもいい体験だった(スタッフのみなさんありがとうございました)。その後もなんやかんやあって忙しい日が続いている(まだ落ち着かない)ので感想を書くのがすっかり遅くなってしまった。
発表内容まとめ
- アメリカ式ソフトウェア開発方式はどこへ向かっているのか
- あじゃてく Lightning Talks
- withコロナ時代のアジャイルとコミュニケーション 〜効果的な場作りとツール〜
- 新しい技術をアジャイルなマインドで進めていく
アメリカ式ソフトウェア開発方式はどこへ向かっているのか
川口 耕介 さん
アメリカ式ソフトウェア開発方式
車を例に、いかにそれが良いものであったとしても文化の違いによっては売れない。アメリカで上手くいったとしても同じものを日本に持ってきて上手くいくかどうかはわからない。ソフトウェア開発においてもそれは同じ。昔会社の先輩が文化の違うところで同じやり方をしたところで上手くいくわけではないと、まったく同じことを言っていたのを思い出した。またソフトウェアプロダクトは子育てに近いものだと言っていたのが印象的だった。比喩としてはとてもしっくりくる。だからこそ、常にベストを尽くす(ベターを目指すというか)必要があるなと感じた。あともうひとつ印象に残ったのは、「開発者の生産性を上げる環境」を自分たちで作るエンジニアがいる会社は強いという話。
withコロナ時代のアジャイルとコミュニケーション 〜効果的な場作りとツール〜
平鍋 健児 さん
www.slideshare.net
場作りの重要性について。場の力が及ぼす空間の影響力はとても大きなもの。場が生まれることで勢いがついて、想定以上のパフォーマンスを発揮したり一体感を得られることはある気がする。今自分は組織に対して働きかける立場にいるが、何かをするにしてもイマイチこうなんというかグッと大きな動きに繋がることがなく、どうしたら活気づかせることができるかなと悩むことが多かった。そういったところに今回のお話を聞いていて、もしかしたらこれが一つの答えなのではと思った。場を作ること。これを積極的にやってみようと思う。他にはリモート環境下におけるチームビルディングでタックマンモデルを短いスパンで繰り返していく話が参考になった。継続的なチーム・信頼関係づくりは新たな発見だった。
新しい技術をアジャイルなマインドで進めていく
中村 薫 さん
アジャイルの知識があっても実践できないが、実践できないまでもアジャイルのマインドセットが実務に生きるという話があって、これは自分にも刺さるところがあって共感した。今の環境もアジャイルでやっているわけではないが、その考え方、とくにスクラムの理論にある透明性・検査・適応や5つの価値基準などが自分を支えになっている。またHoloLensが動いているところを初めて見た。娯楽モノとしても面白いし、現場作業などの実務にも応用が効いて将来性を感じた。
まとめ
- 文化・土台にあるものをしっかり考え許容する
- 場作り大事。場を作ってみよう
- アジャイルなマインドで変化を受け入れる
次回は2021年1月23日(土)とのこと。ぜひ参加したい。
余談
今回Discord初体験だったがなかなか良かった。チャットに声が混ざるとまた違った体験になり、色々な部屋に行ったり来たりできるのも面白い体験だった。また試してみたい。
Python学習メモ:特殊メソッド
特殊メソッド
特殊メソッドとは、Pythonが暗黙的に呼び出す特別なメソッド。メソッド名の前後にアンダースコア2つが付いているのが特徴。例として、組み込み関数len()は引数に渡したオブジェクトの特殊メソッド__len__()を暗黙的に利用する。
class A: def __len__(self): return 5 a = A() len(a) # 5
特殊メソッドの例
__str__()、__repr__()
どちらもオブジェクトを文字列で表現する特殊メソッドだが用途が異なる。__repr__()はデバッグなどに役立つ情報を提供するために利用される特殊メソッド。対話モードでオブジェクト名のみを入力した際にも__repr__()が呼ばれる。__str__()は、組み込み関数のprint()やstr()、f’{}’などで利用される文字列を返す特殊メソッド。このとき__str__()が実装されていない場合は__repr__()が呼ばれる。
__bool__()
Pythonではすべてのオブジェクトが真理値評価でき、偽となるオブジェクト以外は全て真となる。ユーザー定義のクラスやインスタンスはデフォルトで真と評価されるが、これを実装するとその判定処理を変更することができる。なお真理値評価に影響する特殊メソッドは__bool__()のみではなく、__len__()も該当し、__len__()が0を返すとそのオブジェクトは偽となる。
__call__()
これを実装したクラスでは、インスタンスを関数のように呼び出すことができる。インスタンス名()とすれば、__call__()で定義された処理が実行される。
__setattr__()
__setattr__()は属性への代入で呼ばれる特殊メソッド。__setattr__()を利用して特定の条件下でしか実行されないように制限するなどできる。なお__setattr__()内で属性への代入をすると再帰的に__setattr__()が呼ばれることになりRecursionErrorとなる。このため、__setattr__()内で自分自身に属性を追加する際は、必ず組み込み関数super()を使って基底クラスの__setattr__()を呼び出す。
__delattr__()
属性の削除時に呼び出される以外は__setattr__()と同じ。
__getattr__()、__getattribute__()
__getattr__()は属性辞書(__dict__)に存在しなかった際に呼ばれ、__getattribute__()はすべての属性アクセスで呼び出される。これらの特殊メソッドを使用すると、実際にはインスタンスが持っていない属性でもあたかもその属性をもっているかのようなふるまいを定義することができる。
__iter__()、__next__()
for i in x と書いたとき、for文はxの__iter__()を呼び出し、その戻り値を利用する。この戻り値はイテレータと呼ばれ、__iter__()と__next__()が実装されている。__next__()はループのたびに呼ばれ、for i in x のiに渡される。__next__()で返す値がなくなった際にはStopIterationを送出してループを終了させる。なおPythonにはイテラブルオブジェクトという言葉がよく出てくるが、イテラブルと イテレータは異なる概念なので注意。
- イテラブル:for文や内包表記で使えるオブジェクト
__iter__()を実装したオブジェクト
__iter__()の戻り値は任意のイテレータ - イテレータ
__iter__()と__next__()を実装したオブジェクト
__iter__()の戻り値は自分自身(self)
その他の特殊メソッド
その他の特殊メソッドは 3. データモデル — Python 3.9.0 ドキュメント を参照。
特殊メソッドは暗黙的に呼ばれ、標準的な動作をフックして自分が意図した動作に変更することができるので上手く使えば非常に強力な機能だが、反面上手く使えないとその強力さゆえに危険なものにもなり得るように思う。しっかりとした知識と理解がないと使いこなすのは難しそう。
Python学習メモ:モジュール
モジュールとスクリプト
Pythonのクラスや関数の定義が書かれた.pyファイルをモジュールという。スクリプトとも呼ばれるが、両者に明確な違いはない。用途として、python3コマンドから直接実行するものをスクリプト、Pythonコード中で読み込んで利用するものをモジュールとしている。なおモジュールを利用する際はimportを用いる。詳細は6. モジュール — Python 3.8.6 ドキュメントを参照。
python3コマンドからの直接実行
python3コマンドに.pyファイルを指定すると、スクリプトとして実行できる。コマンドライン引数を受け取るときは、sysモジュールをimportすればよい。変数argvにコマンドライン引数が格納されている。
import sys def printHoge(s): print(f'{s} hoge') printHoge(sys.argv[1]) #argv[0]はスクリプト名
なおこのままだとインタラクティブモードで実行すると失敗する。これを回避するにはmain関数を用意する。
import sys def printHoge(s): print(f'{s} hoge') def main(): printHoge(sys.argv[1]) if __name__ == '__main__': main()
スクリプトとしても実行したいモジュールがあった場合、if __name__ == ‘__main__’ とすることでこれを実現できる。モジュールの名前を表す__name__変数が、python3コマンドで呼び出す際は__main__となるためである。
パッケージ
モジュールはクラスや関数などが定義されたファイルだが、プログラムの規模が拡大するにつれて数も増え、適切に管理する必要も出てくる。それらの複数のモジュールをまとめる機能をパッケージという。パッケージの実態は、モジュールやサブパッケージを集めたディレクトリである。通常はパッケージの目印として、__init__.pyを配置する。パッケージの作成手順は以下のとおり。
パッケージ内のモジュールのインポートは以下のようにする。
from {パッケージ名} import {モジュール名}
__init__.py
__init__.pyにはパッケージの初期化を行う機能もある。当該ファイルに書かれたコードは、パッケージがインポートされると一番初めに実行される。例えばここにimport文を書くことによって、パッケージの使い勝手を向上させたりすることができる。
Python学習メモ:クラス
クラス
クラス定義
Pythonのクラス定義は以下の通り。
class クラス名(基底クラス名): def メソッド名(引数, …): 処理 return 戻り値
クラスを継承したい場合はクラス名に()をつけて指定する。省略するとobjectクラスを継承する。
インスタンス生成
クラスオブジェクトに()をつけて呼び出すとインスタンスが作成できる。オブジェクトに渡された引数は、作成されたインスタンスのメソッド __init__()に渡され、インスタンスの初期化に利用される。
class MyClass: def __init__(self, num): self.num = num def printNum(self): print(num) x = MyClass(10) x.printNum()
インスタンス
インスタンスメソッド
インスタンスメソッドはクラス定義中に定義される関数。通常の関数定義と異なる点は、第一引数が必ずインスタンス自身のオブジェクトになること。仮引数名には慣例としてselfが使用される。
インスタンス変数
インスタンスの属性に値を代入すると、インスタンス変数を定義できる。インスタンス変数は、インスタンスごとに独立した値となる。インスタンス生成後に変数を定義して使用することができる点は、ちょっととっつきにくいかもしれない。クラス共通の変数にしたい場合は、__init__()を使用する。
__init__()
インスタンスの初期化を行う特殊メソッド。インスタンスの生成直後に自動で呼び出される。__init__()でインスタンスに属性を追加すると、 このクラスのすべてのインスタンスがその属性を持つことになる。
なんとなくコンストラクタをイメージしそうだが、__init__()はインスタンス生成後に呼び出される点で異なる。なおPythonにおけるコンストラクタにあたるメソッドは別にあり、__new__()である。クラスオブジェクトを呼び出しインスタンス化を行った時の処理の流れとしては、まず始めに__new__()が呼びだされ、その戻り値が__init__()の第一引数selfに渡される。
Pythonではインスタンスの初期化は殆ど__init__()で対応でき、__new__()を使用することは少ないそう。また__new__(()はインスタンスを戻り値とすることから、これを変更してしまうと使用者から想像できない問題を引き起こすことがあるため、__new__(()の使用はどうしようもない場合を除いて基本的に避ける。
プロパティ
@propertyでインスタンスメソッドを定義するとプロパティになる。 プロパティは()なしで呼び出せ、変数のように扱える。@プロパティ名.setter でセッターを定義する。
class MyClass: def __init__(self, num): self._num = num @property def Num(self): return self._num @Num.setter def Num(self, value) self._num = value x = MyClass(100) x.Num # 100 x.Num = 200 x.Num # 200
プライベート属性
Pythonにはプライベート属性がないが、属性の先頭にアンダースコア2つ(__)をつけると名前修飾が行われる。名前修飾はサブクラスでの名前衝突を防ぐために行われ、クラス名がアンダースコアの前につけられる。例えばMyClassにある__numはMyClass__numとなる。外部からアクセスする際は名前修飾後の変数である必要があり、そのままだとアクセスできない。
クラス変数とクラスメソッド、スタティックメソッド
クラス変数
クラスオブジェクトに紐づく変数。クラスインスタンスからも参照可能で、すべてのインスタンスで同じ変数が共有される。クラス変数を更新する場合はクラスオブジェクトを介して行う必要があり、インスタンスを介して代入すると、新たなインスタンス変数が作成されることになる。また同名のインスタンス変数が定義された場合はそちらが優先される。
クラスメソッド
クラスオブジェクトに紐づくメソッド。@classmethodを付けることで定義できる。第一引数にクラスオブジェクトが渡されること以外はインスタンスメソッドと同様に扱える。この場合、仮引数名にはselfではなくclsとすることが慣例とされる。
スタティックメソッド
@staticmethodとするとスタティックメソッドになる。スタティックメソッドの引数にはインスタンスやクラスが渡されることはない。つまりただの関数と同じで、クラスなしに関数のみを定義できるPythonでは使われることはあまりないらしい。
継承
メソッドのオーバーライド
基底クラスが持つメソッドと同名のメソッドを定義するとオーバーライドできる。オーバーライドしたメソッド内で基底クラスのメソッドを使用したい場合はsuper()を利用して明示的に呼び出す。
objectクラス
Pythonでは、組み込み型を含めた全てのクラスの基底クラスとしてobjectクラスがある。そのため組み込み型を継承してサブクラスを定義することもできる。
Python学習メモ:関数
関数
Pythonの関数定義は以下の通り。
def 関数名(引数1, 引数2, …): 処理 return 戻り値
カッコの代わりにコロンを使うところは制御構文と同じ。引数、戻り値は不要ならそれぞれ省略できる。 Pythonでは関数名はスネークケースが用いられるのが一般的なよう。
デフォルト引数を使用する場合は引数名に=デフォルト値とする。
またPythonでは関数はオブジェクトであるため、変数に代入したりできる。
def printHoge(): print(‘hoge’) func = printHoge func() # printHogeと同じ
関数のさまざまな引数
位置引数
関数の呼び出しで、仮引数名を指定せずに渡す実引数を位置引数という。C++やC#などの言語での呼び出し方法。
hogeFunc(1,2)
キーワード引数
関数の呼び出しで、仮引数名を指定して渡す実引数をキーワード引数という。キーワードを指定する場合は、順番に影響しない。
def hogeFunc(hoge, piyo): print(hoge + piyo) hogeFunc(piyo=‘aaa’, hoge=‘bbb’)
可変長の位置引数
仮引数名に * をつけると、可変長の引数を定義できる。
引数名には慣例として、*argsとすることが多い。
def hogeFunc(*args): for i, e in enumerate(args): print(f’arg{i+1} :{e}’) hogeFunc(‘hoge’, ‘piyo’, ‘fuga’)
可変長のキーワード引数
仮引数名に ** をつけると、可変長のキーワード引数を受け取る関数が定義できる。
引数名には慣例として、 **kwargsとすることが多い。指定された引数は辞書で受け取る。
def hogeFunc(**kwargs) for key, value in kwargs.items(): print(f’{key}: {value}’)
キーワードのみ引数
呼び出し時に仮引数名の指定が必須になる引数。キーワードのみ引数としたい仮引数の前に*を指定する。
def hogeFunc(hoge, *, piyo): # piyoがキーワード必須になる print (hoge+piyo) >>> hogeFunc('hoge', 'piyo') # キーワードなしで呼ぶとエラー Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: hogeFunc() takes 1 positional argument but 2 were given
位置のみ引数
仮引数名を指定するとエラーになる引数。位置のみ引数としたい仮引数の前に / を指定する。 Python3.8からユーザー定義関数でも使用できるようになった。
引数リストのアンパック
関数呼び出し時に * でリストや辞書から引数を展開する機能。
hogeList = [‘hoge’, ‘piyo’, ‘fuga’]
hogeFunc(*hogeList) # hogeFunc(‘hoge’, ‘piyo’, ‘fuga’)
同様にして ** を使用すると、辞書に格納している値をキーワード引数として渡すことができる。
lambda式
Pythonにおけるlambda式は以下のとおり。
lambda 引数1,引数2, … : 戻り値になる式
lambda式は関数にするほどでもないちょっとした処理に使うと便利。またlambda式は関数オブジェクトなので、関数を引数に取る関数にも使用できる。
Python学習メモ:データ構造
データ構造
None
C++やC#などのnullに相当し、シングルトンである。
条件式で使うと偽となる。あるオブジェクトがNoneかどうかを判定するにはisを使用する。
==がeq()をオーバーライドして結果を変えられるため。isの場合はその心配がない。
hoge = None if hoge is None: print(‘hoge is None’) else: print(‘hoge is not None')
bool型
True/False。Pythonではbool()を用いることですべてのオブジェクトが真理値判定できる。
bool(None) # False bool(‘hoge’) # True
ブール演算には or, and, not の3つがある。or, andともに真ならboolを返すのではなく、オブジェクトが返るところに注意。andの場合、x and y が真ならyが返る。
x = 1 y = 2 x or y # 1が返る x = None x or y # 2が返る x = 2 x and y # 2が返る
数値型
Pythonではint, float, complex(複素数型)の3つがある。異なる型を含む演算の結果の型は complex > float > int となる。
complexを含む場合はcomplex、floatとintならfloatとなる。演算子は四則演算に加えて、%(剰余)、//(結果の切り捨て)、**(n乗)がある。
2 ** 2 # 2の2乗
数値に_(アンダースコア)を入れると見やすくかける。
1_000_000 # 1000000
文字列型
Pythonではstrが文字列型にあたる。シングルクォートまたはダブルクォートで文字列型となる。
文字列中の改行は¥nで可能だが、’’’ または “”” でも可能。カッコでくくられた複数の連続する文字列は1つの文字列として見なされる。
長い文字列を見やすい単位で区切ったりするときに使える。
hoge = (‘ho’ ’ge’ ) print(hoge) # ‘hoge'
文字列に対して * と数値を使用すると、数値回繰り返した文字列になる。なおもとのオブジェクトはそのままなので、別の変数に代入するなどして使用する。
hoge = ‘hoge’ print(hoge*5) #hogehogehogehogehoge
Pythonには f-string という文字列リテラルがある。先頭にfをつけて定義し、文字列中に{}でくくった変数や式を記述すると、実行時に置換される。
fruit = ‘an apple’ f’This is {fruit}.’ # ’this is an apple.'
ちなみにPythonではstrオブジェクトが標準で存在しているので、うっかり変数名にstrを使用しないようにする。
配列
Pythonで配列を扱うデータ型にはlistとtupleがある。listは[]を使って初期化する。またlist()を使用すると、新しいリストを作ることができる。
list(‘hoge’) # [‘h’,’o’,’g’,'e']
追加はappend、挿入はinsert、削除はpop、removeがある。そのほかのメソッドについては5. データ構造 — Python 3.8.6rc1 ドキュメントを参照のこと。
items = [‘hoge’] items.append(‘fuga’) # [‘hoge’, ‘fuga’] items.insert(1’piyo’) # [‘hoge’, ‘piyo’, ‘fuga’] print(items.pop(2) # [‘hoge’, ‘piyo’]
リストに対して、変数名[先頭のインデックス:末尾のインデックス]とすると、その範囲のリストが作成でき、これをスライスという。
items = [‘hoge’, ‘piyo’, ‘fuga’] items[0:2] # [‘hoge’, ‘piyo’]
tupleは不変な配列を扱う。定義すると以後は変更ができない。
,(カンマ)で初期化すればタプルが作成できるが、可読性を上げるためにカッコを使うことが多い。
辞書型
Pythonではdictで辞書を扱う。
{key1:value1, key2:value2, … }と初期化する。またdict()でも作成できる。
items = {‘hoge’:1, ‘piyo’:2}
追加は新しいキーを指定して値を代入すればよい。削除はlistと同じくpop()やdel文を使用する。 詳細は組み込み型 — Python 3.8.6rc1 ドキュメントを参照。
集合
setとfrozensetがあり、配列(list, tuple)と異なる点は要素の重複を許さず、順番を保持しない点。
setの初期化には{}を用い、{要素1, 要素2, …}とする。set()から作成できる点もほかのデータ型と同じ。
items = {‘hoge’, ‘piyo’} items.add(‘fuga’) # 追加 items.remove(‘piyo’) # 削除
順番を持たないため、インデックスでのアクセスはできない。またpop()で要素を取り出せるが、何が返ってくるかは不定となっている。さらにfor文にも使用できるが、これも順番は不定。
frozenset型は不変なset。
setは集合型なので集合演算が可能。 |, -, &, ^ などで集合同士の演算ができる。 set,frozensetの詳細については、組み込み型 — Python 3.8.6rc1 ドキュメントを参照。
5〜8月のふりかえり
4ヶ月経ったので5〜8月のふりかえり。以下は前回。 aganik.hatenablog.com
今年の目標
まずは今年はじめに立てた目標をおさらいしておく。
意義目標
- QoLを高めつつ、継続して成長できるエンジニアになる
行動目標
- アウトプットを重視する
- 書籍を年間20冊以上読む
- 使える言語を一つ増やす
- 旅行する
アウトプットを重視する
ブログのペースは概ね週一を保てている。一度だけ飛ばしたことがあったが、単にネタがないことが要因だった。アンテナを拡げてアイデアを整理・ストックしておくようにしたい。
ブログを始めてからアウトプットを意識しながらインプットするようになったと思う。書籍を読んだりしても、文章化して自分の言葉で要約できるかどうかで理解度を確認するようになった。今までなんとなくで読んでいたところもあったので、この変化は嬉しい。
読んだ書籍など
- スクラムガイド
- ラーニングパターン
- SCRUM BOOT CAMP THE BOOK
- WHO YOU ARE
- オブジェクト思考UIデザイン(途中)
- モダン・ソフトウェアエンジニアリング
- 人工知能は人間を超えるか
書籍は4冊。ペースは悪い。読んだ内容をアウトプットするようになったからというのもあるが、 最近仕事が多く帰宅時間が遅くなっているのでそもそも時間が取れていない。目標到達は厳しそう。
使える言語を一つ増やす
漸くPythonの学習を始めた。9月中くらいには一通り学習して何か作りたい。
旅行する
目標達成。 8月下旬に和歌山へ旅行した。子供達も(入るのは)初めての海や、アドベンチャーワールドなどが楽しかったようで良かった。湯快リゾートには初めて泊まったが、プール・卓球・カラオケ・漫画/ゲームコーナー・マッサージチェアなど思いの外サービスが充実していて良かった。コロナ禍の中なかなか遠出はしにくいが、感染症対策をしっかり行って機会があればまた出かけるようにしたい。なお旅中に行ったアドベンチャーワールド・ホテルは感染症対策をしっかり行っており好印象だった。
その他
勉強会関連
6月にスクラムに関する勉強会を開催した。発表する側は久しぶりだったので緊張したがいい経験になった。CSMを更新するきっかけにもなったし、機会をもらえたことに感謝したい。また社内の勉強会にもちょくちょく参加するようになった。社内の他部署の人たちとも交流の幅を広げていければと思う。社外のイベントにも参加した。これまた久しぶりの参加だった。人見知りでコミュ障の自分はどうも最初の一歩がかなり遠いが、参加するとやはり刺激にもなるしモチベーションが上がるのも実感する。もっと気軽に参加できるようになりたいがどうしたものか。
所感など
1〜4月に比べて動きが多かった4ヶ月となった。今年度から関わっている社内活動によるものが大きい。他部署の人たちともコミュニケーションを取ることも増えたし、それなりに充実している。ただ仕事がオーバーワーク気味になっている。明らかに帰宅する時間が遅くなってしまった。自己啓発や娯楽に使える時間も減ってしまっているのでこのままだとよくない。うまくバランスをとって疲労がたまらないようにしたい。