とりあえずの独り言

テーマは特に限定せず、独り言のように

Qiitaにではなくて、ブログにもアウトプットを増やしていこうと思う

勉強したことをアウトプットすることが重要!!

とはよく聞く言葉だし、その通りだと思う。勉強しただけだと、実際に使ってみたり応用してみたりするとわかってたつもりだったのに「あれ、どうやるんだろ?」って気づくきっかけにもなる。

プログラムだけじゃなくて学校の勉強でも同じだと思うけど、教えてもらった内容を自分の言葉でかみ砕いて説明する。こういう発表の場は、生徒全員にそういう機会が与えられればいいんだろうけど。。。さすがに時間が足らないから無理だろう。

互いに苦手な教科を教えあうとかでも、効果はあると思う。そういや、俺は小学校のときよく勉強教えてもらったんだけど。。。。兄貴が教え上手でわりと成績よかったのは俺のおかげか(関係ないが、ドヤァ)

アウトプットする媒体はいろいろあるけど。。。

Qiitaや、noteといったアウトプットできる媒体ってのは、近年はそろっていると思う。
たまにポエムとかいろいろ言われがちなものもよく見るけど、Qiitaなどにアウトプットするのは個人的にはハードルが高く感じてしまう。

少し前は、Qiitaにも投稿はしてたんだけど。。。最近はほぼROM専になってる。 Qiitaとかにアウトプットする場合、しっかりと検証して、他の人にも読んでもらう文章をかいてetcとか考えてしまう。

たまにしっかりとした内容のものを投稿するならいいけど、頻繁に細かくアウトプットしたい!って思ったときに、中途半端な内容を残しづらいなぁというのが個人的印象

ブログなら気楽にアウトプットできる

Qiitaと違って、新規ブログはアクセスも伸びづらいし、「いいね」みたいなのがすぐ付くわけじゃない。だけど、自分のブログだし検証内容が十分でなくてもメモ書き程度に残すだけでも問題ない。

この気楽さはブログならではかな、と思う。学習ログや作業ログを残す感じで、メモっとけばいい。ある程度メモ書きがたまってきたら、それをまとめて清書して、Qiitaにでも投稿すればそれなりのものが出来上がってるんじゃないだろうか?

アウトプットは頻繁に

”今日学んだこと”とかを頻繁にアウトプットし続けるほうがいい気がする。アウトプットし続けていくうちに、表現することのハードルが下がっていくと思う。

書籍を出版するわけじゃないんだから、身構えずに気楽にアウトプットできたらいいなぁ・・・(っと自分に言い聞かせる)

一人で勝手に忙しくなってるだけじゃない?

「いっぱいやることがあって、そこまで対応してる時間がないんです!忙しいんです!!」

勝手に忙しくなってるだけの一人相撲じゃないの?本当に忙しい?って聞きたくなる人がいる。



まず、マスタスケジュールもまともに作っていない。ドキュメントもしっかりとしたものは作っていない。それで、何を信じればと。。。 忙しいとだけ言われても、対策できないですよね?

  • 作業量が単純に多い
     ⇒ 人を投入すれば解決できる
  • 難易度の高い課題がある
     ⇒ 解決できそうな人を連れてくる。もしくは、代替案の検討など
  • 担当してる人しか作業ができない(属人化してしまっている作業、深い仕様の理解が必須な作業など)
     ⇒ 持っている他タスクを引き取り、集中して作業してもらう

他にもいろいろあるだろうけど、こんな感じで対策も異なってくる。

そもそもスケジュールを立ててないんだから、その作業ってどれだけ遅れてるの?って聞かれても答えられないよね。
他のドキュメント類もしっかりとは残さず、メモ書き程度。しかも仕様変更されても、印刷した紙にメモする程度でそれってファイルに反映しました??

ドキュメントを細かく残しすぎてもメンテが大変だからとかあるとは思うが、必要最低限の資料は残せよと。残さなくていいドキュメントは、チームで話し合って、ここまでは残そう、でもこれはいらない。とか話し合って決めるもの。決して面倒だから残さないわけではない。

必要なドキュメントも残さない手抜きを積み重ねた結果、本番リリース直前で痛い目見てるだけじゃないの?

【SQLAlchemy】sessionの作成はどの方法がいいのか?考えてみた

概要

SQLAlchemyでは、sessionの作成方法が複数あって結局どれがいいの?っていうのをいろいろ考えてみた。

ちなみに、Flaskなどのフレームワークを利用している場合はSQLAlchemyをラップしたFlask-SQLAlchemyなどがあるのでここら辺を利用するとsession周りは良しなにやってくれます。

フレームワークを使わないような、ツールやバッチ系などではSQLAlchemy単体で使うことも多いと思うのでそういう人向けです。

参考:
SQLAlchemyのSession生成方法 - Qiita
【PythonのORM】SQLAlchemyで基本的なSQLクエリまとめ - Qiita
Using the Session — SQLAlchemy 1.3 Documentation

一つ目のリンクと結構重なるところが多かったorz
ただ、結論が若干違うのでパk・・・引用しつつ書き残したい。

sessionクラスを使う

from sqlalchemy import create_engine
from sqlalchemy.orm import Session


DATABASE = "sqlite:///localdb.sqlite3"
engine = create_engine(DATABASE)

session1 = Session(
    autocommit=False,
    autoflush=False,
    bind=engine)

session2 = Session(
    autocommit=False,
    autoflush=False,
    bind=engine)

print(session1)
print(session2)
print(session1==session2)

## 結果 ##
# <sqlalchemy.orm.session.Session object at 0x00000214C12E98C8>
# <sqlalchemy.orm.session.Session object at 0x00000214C12E9A48>
# False

一番簡単なやり方。
Sessionを呼ぶたびに、新しいインスタンスが作られる。

ちなみに、Sessionクラスはスレッドセーフではないため、setting.pyに記載して使いまわさないほうがいい。(絶対単一スレッドでしか起動しないなら関係ないが)

session_markerクラスを使う

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker


DATABASE = "sqlite:///localdb.sqlite3"
engine = create_engine(DATABASE)

session = sessionmaker(
    autocommit=False,
    autoflush=False,
    bind=engine
)

session1 = session()

session2 = session()

print(session1)
print(session2)
print(session1==session2)

## 結果 ##
# <sqlalchemy.orm.session.Session object at 0x000001379B0C9788>
# <sqlalchemy.orm.session.Session object at 0x000001379B0C9988>
# False

Sessionクラスを使うときと同様にsession()を呼ぶたびに新しいインスタンスが作成される。 違いは、毎回設定を渡さなくてもいいということぐらい。

上でも書いたように、SessionクラスはスレッドセーフではないのでSessionインスタンスは使いまわさないほうがいい。 だから、sessionmarkerで設定のみsetting.pyに記載して、それぞれの個所でsession()を呼ぶという使い方になるんだろうと思う。

scoped_sessionクラスを使う(オススメ)

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session


DATABASE = "sqlite:///localdb.sqlite3"
engine = create_engine(DATABASE)

session = scoped_session(
    sessionmaker(
        autocommit=False,
        autoflush=False,
        bind=engine
    )
)
session1 = session()
session2 = session()
session.remove()
session3 = session()

print(session1)
print(session2)
print(session1==session2)
print(session3)
print(session1==session3)

## 結果 ##
# <sqlalchemy.orm.session.Session object at 0x000002A8E2699848>
# <sqlalchemy.orm.session.Session object at 0x000002A8E2699848>
# True
# <sqlalchemy.orm.session.Session object at 0x000002A8E2699988>
# False

今までの2つと異なる点は、sessionを呼んでも同一のインスタンスを返してくれること。もちろんsession.remove()すれば新しいインスタンスを返してくれるようになる。
また、このsessionインスタンスはスレッドローカルを利用しているためマルチスレッドで実行させたいといったときは、これを利用する。

実際に実装するときは、

  • setting.pyの中にscoped_sessionでsessionクラスを定義する
  • dbパッケージを作る
  • dbパッケージの__init__.pysetting.pyimportする

みたいな感じになるんじゃないだろうか?

session のクローズについて

session.close()メソッドでセッションを閉じれるが、scoped_sessionクラスで作成したインスタンスを使いまわす形になるのでcloseする必要はなさそう。Session()で都度作成するパターンの場合は、使い終わったらcloseは必要だろうけど、その点でもscoped_sessionクラスはよさそう。

補足(auto_flush, auto_commit設定について)

ちなみにauto_flush, auto_commitFalseでいいんじゃないかなー?

Transactions and Connection Management — SQLAlchemy 1.3 Documentation

auto_commitはlegacy modeとか書いてあるし。

ちなみに、flushとcommitでflushしなきゃいけないパターンについては、

【SQLAlchemy】flushとcommitの違い - とりあえずの独り言

で少し書いた。

補足(トランザクションについて)

トランザクションの開始とかは特に、明記する必要もない。auto_commit設定がTrueになっている場合は、明示的にトランザクションを設定する場合もあるらしい。

auto_commitFalseの場合は、コミットした段階で新しいトランザクションが開始される。scoped_sessionで作成したインスタンスは、スレッドローカルを使うのでマルチスレッドで動作しても違うトランザクションになるので並列実行しても問題なさそう。(スレッドローカルとか、マルチスレッドとか苦手でいまいち理解しきれていない・・・)

プロパーとそれ以外の社員で、使用PCの権限レベルが違うのはどうにかしてほしい

PC(windows)の権限が引きすぎて、管理者権限パスワードのダイアログが出るたびにプロパーの人に入れてもらわないといけない件。。。

勝手に変なプログラムインストールされたくないとかいう気持ちはわかるよ?

でもこっちは開発してるわけで、システム変数をいじることもあるし、管理者権限が必要なパスのファイルを編集するのが必要な時もあるんだよ
何を編集すればいいか決まっているときはいいけど、環境面で嵌ってしまったときとかは試行錯誤しなららやりたいことも多い。

そしたら、かなりの頻度でパスワード入力を求めることになるし、すごく非効率
そもそもプロパーだったら、管理者権限持ってても問題ないという考えはどうなの?そもそも、あの人たち仕事できないじゃんって言いたい!!

~と同じようにとか簡単に言っちゃう人とは仕事したくない

何かの移植とか、別プロジェクトの似たような機能を追加するとか、リプレイス案件とか
そんな感じの案件だと、よく「〇〇と同じように追加して」とか「既存と同じように」とか言葉が飛び交いがち

まぁ、要件定義でお客さんがこいう言葉で伝えてくるのは、理解できるんだよ。
お客さもしたいことはあるけど、具体的なことまで把握していなかったり、システム全体のつながりまでわかっていなかったりする。
やりたいことだけ伝えようとすれば、わりと抽象的になりがち。だけど、あいまいな表現を読み解いて具体的な言葉にして詰め合わせていくことも、エンジニアの仕事ではあると思う。



ただ、同じプロジェクトのメンバーからこの言葉が出てきたら、「はぁ?ちゃんと考えて物言ってます?」って聞き返したくなる

~と同じように、って言葉はすべてを抽象化して覆い隠してしまう。。。だから、問題ないと思い込んでしまう。

参考にするのは、問題ないよ?
でも、完全に同じわけじゃないよね。そもそも同一なら、自動化なり共通化なり多少なりともされているはずだし 同じだからということを言い訳にして、タスクを無理やり一つ消化していないか?
後々困るの自分自身であり、チームなんですが。。。。

よく教科書とか本だけ見て、できる気になっている学生みたいな感じ。いざやってみようという段階になって、いろいろと問題が発掘されるというね


A「〇〇へリリースするときの手順ってどうなってるんですか?」
B「XXへリリースした時と同じようにすればいいから」
A「えっ、でも〇〇とXXってサーバー構成違いますよね?」
B「・・・・」

リリース前日の出来事

【SQLAlchemy】flushとcommitの違い

session.commit()をすると、session.flush()も一緒に実行するらしくcommit()だけでもいいんじゃないかと思ってた。

だが、commit()だけだと、うまくいかないケースがあったので備考録として残す。 ざっくりというと、思った通りの順番でaddして登録したつもりでもcommit()の時にDBへ送られるsqlの順番は保証できないよというお話

commitとは~、flushとは~と言葉で説明してもわけわからんので、flushを気にする必要があるパターン例でみればわかる気がするので以下掲載

commitについては、DB関連でいっぱい説明あると思うので割愛

flushを意識しないでも問題ないパターン

# マスタに未登録の商品のみ登録する
product_id = info.get('product_id')
product_name = info.get('product_name')
price = info.get('price')

if not db.session.query(Products).filter(Products.product_id == product_id ).first():
   # 商品マスタ登録
    product = Products()
    product.product_id = product_id 
    product.product_name= product_name
    product.price = price 
    db.session.add(product)
    db.session.commit()
  • すでにcommit済みのデータをselectして、利用したりする
  • insert対象が1テーブルだけ、や任意の順番でinsertされようが問題ない 場合など

適切な順番でinsertする必要がある場合(flushする必要あり)

外部キーが設定してある場合など。マスタテーブルのほうにレコードがないと、制約違反で落ちる

product_id = info.get('product_id')
product_name = info.get('product_name')
price = info.get('price')
category_id = info.get('category_id')
category_name = info.get('category_name')

# カテゴリマスタ登録
category = Categories()
category.category_id = category_id
category.category_name = category_name
db.session.add(category)
db.session.flush()  # DBに上のSQLを投げたよーという通知

# 商品マスタ登録
product = Products()
product.product_id = product_id 
product.product_name= product_name
product.price = price 
product.category_id = category_id
db.session.add(product)
db.session.commit()

※ Product.category_id には、Category.category_idへの外部キー制約がついている想定です。

コミット前のinsertデータに対してselectしたい場合(flushする必要あり)

検証はしていないけど、おそらくこのパターンもflushは必要。実際は、何らかのカウントしたり、集計した結果に対して実行はするのだろうけど簡略化のためキー検索を例にしている

# 商品マスタ登録
product = Products()
product.product_id = product_id 
product.product_name= product_name
product.price = price 
product.category_id = category_id
db.session.add(product)
db.session.flush()  

# commit前のinsert情報に対して修正する
if db.session.query(Products).filter(Products.product_id == product_id ).first():
   # ~何らかの処理~(insert結果がおかしかったら,rollbackなどの処理とか)
   # 登録時にflushしていないと、レコードを取得できない

db.session.commit()

【メイドインアビス 深き魂の黎明 】おのれ、ボンドルド。。。

今年、1本目の映画を見に行ってきた
雨だし、9:00~開始でも割と人は入ってた。まぁ、この回に来る人は劇場マナーがいいから快適な視聴環境だった



当初R12を予定していたけど、R15に変更されたことで話題になった

メイドインアビス 深き魂の黎明 」

を見てきた。
軽くネタバレを避けつつ感想は書いたが、人によってはネタバレっぽく感じてしまうかもしれないので・・・・





これR12でやろうとしてたんだよね?そりゃR15に変更になるわwとは思った。それに、TVでやってたら真っ黒になってしまうであろう描写も多く、だからこそ劇場でやってくれたことに大満足!


ボンドルドは、やっぱり外道すぎる。そしてボンドルドの正体もまさに外道。カートリッジぇ・・・


ボンドルドの子供として出てきていたプルシュカ。PVの時点で不穏な空気は感じてたけど、こういう結末たどるかぁ

白笛がの秘密も明らかになり、どうやってライザはこれを作ったのか?とかレグの正体は?とか 次回作につながる伏線もいろいろあって続編も大いに気になる感じ。とりあえず円盤も購入予定

プルシュカの思いも、ボンドルドの外道も、リコが底を目指す理由も
ナナチの「憧れは止められねぇんだ!」っていうセリフに集約されているようだった。