shunshock! (original) (raw)

着弾

コンフォートホテル函館というホテルに泊まりました!

コンフォートホテル部屋

なんと朝食つきです!

コンフォートホテル朝食

www.choice-hotels.jp

本編

U25支援企画

@notch_man さんが登壇するということで参加しました!Smartyのアップデートの話、噂には聞いていたけれど改めて聞くとすごいなあとなりました。

プロファイラ開発者と見る「推測するな、計測せよ」

fortee.jp

バイナリを吐き出すプログラムではなくインタープリタを計測しようとすると、直接バイナリから計測できなくなるので大変そうだなと感じました。

以下めも。

計測を使って仮説検証する。

計測をするために重要なこと。

実世界におけるパフォーマンス改善

普通の Web エンジニアのための様相論理入門

fortee.jp

CTLをテストフレームワークとして使う話。テストがしにくいなと思っていたものでもグラフの構造を使ってテストできるのであれば、やってみたいなと思いました。コンピュータサイエンスにおける様相論理という本を買ってみようと思います。

フロントエンドの現在地とこれから

fortee.jp

フロントエンド書かないので、学習になった。Suspenseとか全然追えてないので勉強したい。

WebTransportは未来の技術?

fortee.jp

HOL問題を解決する話とWebTransportの話

qiita.com

Web TransportはWeb Socketより性能が良いが、仕様が固まっていなかったり、一部で対応していないブラウザがあるとのことでした。Go用のライブラリ作成が卒業研究なので2月にはできるらしい。めでたい。

クレジットカードを製造する技術

fortee.jp

クレジットカードの技術仕様やICチップの話。全然知らない世界で面白かった!秘密鍵の輸送方法が個人的に面白くて、分割して物理輸送するそうです。

Key Note

「アルバイトが書いたコードをバイトと呼びます」「入社日にKDDIに買収される」「ドキュメントのポインタでたらい回しにされて最初に戻る」「"""某社を経て"""」

磨かれた個人技による貢献、できるようになりてぇなあとなりました。

再発明から学習するの、本当にわかる...

表彰式

友人のうーたんさんが受賞されていました!おめでとうございます!!!

ごはん

HAKODATE BEER

@notch_man さん、 @live_in_2107 さんとビールを飲みに行きました!

HAKODATE BEER

https://www.hakodate-factory.com/beer/

チーズの揚げ物

yapcとチーズの揚げ物

まとめ

今年もYAPC最高でした!!! スタッフの皆さん、スポンサーの皆さん、スピーカーの皆さん、ありがとうございました!!!

1日目は、仕事などの兼ね合いであまりいられなかったので2日目がメインでした。簡単な振り返り記事です。

Speech

Unlocking Python's Core Magic

2024.pycon.jp

Pythonに生えているAPIの力を引き出すためのテクニックをミニマムなコードとOSS(Airflow)のコードで解説する興味深い内容でした。

Slideは掲載されていないですが、気になった方は下記の内容を調べると良いと思います!

Rustを活用したPythonライブラリの開発

2024.pycon.jp

maturinを使うといいぞ、ただ、パフォーマンスはCythonほどではないぞという内容だった。僕含め、会場にRustceanが多かったのとパフォーマンス計測がCythonに有利に見えたので、ちょっと質問時間ヒヤヒヤしてた。

github.com

個人的にはRustで書いたときに、Pythonのstubファイルが生成されるかと、Pythonの実行時の型チェックを自動で書いてくれる仕組みがないか気になった。質問した感じ、前者はあるが、後者はなさそう。

The Wheelhouse of Horrors

2024.pycon.jp

Pythonのwheel fileの話。普段あまり聞かないトピックだったので面白かった。so fileが別のso fileを参照して辛いので、外部ライブラリの依存を最小限に、必要ならwheelの中にという話が、他のシステムでもありそうだよなと思った。

Why Knowing Cython Helps in Understanding Python: A Deep Dive into Cython & PVM

2024.pycon.jp

github.com

Cythonの話を聞いた。速いという話はよく聞くけど、理由は知らなかったので勉強になった。コンパイル(.c -> .o -> .so)とGILの脱出を見てそりゃCythonの実行速度が速くなる訳だ、と納得した。

Keynote

2024.pycon.jp

stringオブジェクトにメソッドがない時代があったなど、歴史の話が面白かった。

インタープリタが循環参照で死ぬという話もありました。数日前にRustのgenerics周りのcompilerの話を聞いていた身からすると、まあそうなるよねというお気持ちに..

作るの大変そうなソフトウェアでバグが出るのは定めなのかもしれないですね。

uniquevision.connpass.com

Booth

Stockmarkさんのブースで公開されていたナレッジグラフのRAGのdemoが凄すぎて、ナレッジグラフの本をすぐに読もうと思いました。見た感じ画像からRDF(Resource Description Framework) っぽいグラフを生成していたけれど、ソースが画像でなくとも動きそうな気がした。

JetBrainsさんのトートバッグおしゃれすぎて、早速導入しました。ほとんどのIDE触っていて、お世話になっているので身につけられるの嬉しすぎる。

自己紹介


平和な日本の時間事情


日本はいいぞ、なんてったって、単一のタイムゾーンで夏時間が存在しないからね!

日本標準時JST)は、日本国内で公式に採用されている標準時であり、協定世界時(**UTC)に9時間**を加えた時間。

UTCの魔の手がやってきた!!!


あるCloudサービスを使っていたときに、「時刻設定はUTCで指定できる」と言われた。

える、知っているか、UTCで指定できるということは、JSTでは指定できないんだよ。

手軽かつ安全にTimezoneの変換したい


Timezoneを使う機会はだいたい、コードの実行するタイミングを指定するタイミングでやってくる。時間を間違えると、他の更新日時の関係で動かないコードがあれば、大惨事に。

設定ミスはしたくないが、いちいちブラウザを開くのも面倒。

SystemのPythonに変更を加えたくない


CLIで手軽に使えるものはないか」とChatGPTに聞いたら、Python製のソフトウェアをお勧めされた。しかし、globalでpipを使うと月日とともに崩壊する未来があるので、systemのPythonはできれば使いたくない。

とはいえ、それ以外の方法で作ると過剰な気がする。

Pythonにご飯を食べさせてもらっている立場なので文句を言うつもりはない

補足: Pythonの開発環境が年々良くなっている話(余ったら話す)

少し前まで、Docker経由が前提となりがちだったPythonだが、uv によるプロジェクトの一元管理が可能になったため、docker経由しなくても十分開発できるようになりつつある。

uvとは、次世代Python Package Managerのryeの作者であるMitsuhiko氏とastral社がタッグを組んで開発をしているPython Projectのマネージャー。RustのCargoに近い。

uvでは以下の要素を管理できる。

docs.astral.sh

CLIはできればワンバイナリで入って欲しい


汎用言語のインタープリターが強力な手段であることは、理解しつつも、仕事で使うツールであれば、持ち運びのしやすいバイナリ形式、特に単一のバイナリ形式で欲しい。(雑に usr/local/bin/ に突っ込んだら動いてほしい)

せっかくなので作ることに。

補足: インタープリタ型言語の実行方法

Pythonなどのインタープリタ型の言語(特にASTを利用する言語)の場合、以下のような工程をインタープリタというソフトウェアが行い実行される。

※ 実際には、JITコンパイル(Just In Compile)というプログラムの実行時にバイトコード中間言語をネイティブコード(機械語)に動的にコンパイル(変換)する技術があり、JavaScriptRubyなど主要言語で採用されている。 ※ オペコードを生成しなくても動かすことは可能、例えば、ASTを巡回しながら順番に実行する方法がある。

Rustを採用した背景


Rustを使った背景としては以下の要素がある。

github.com

個人開発

自分用のツールだったので、Rustを導入しやすかった。

チームで使うツールであれば、(よほどの理由がない限り)チームメイトが慣れている言語や、それに近い言語を選定する傾向があるので、ここは大きいと思う。

単一のバイナリで動かせる

持ち運びが便利なツールが欲しくて、自作した。つまり、簡単に使える単一バイナリのツールが欲しかった。

使いやすい入力パーサーがある

Rustには、使いやすいCLIのユーザー入力のパーサーがあり、開発がしやすい。

use clap::Parser;

/// Simple program to greet a person #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { /// Name of the person to greet #[arg(short, long)] name: String,

/// Number of times to greet
#[arg(short, long, default_value_t = 1)]
count: u8,

}

fn main() { let args = Args::parse();

for _ in 0..args.count {
    println!("Hello {}!", args.name);
}

}

https://github.com/clap-rs/clap

この件以来、RustでCLIを作ることが多くなったので、どう使うのがいいか色々検証している。最近の趣味のプロジェクト(AST巡回型言語)だと以下のようなReceiverを作ってwrapしている。

※ これが最適という主張ではないので注意

use clap::{Arg, ArgAction, ArgMatches, Command};

pub(super) struct Receiver {}

impl Receiver { pub(super) fn new() -> Self { Receiver {} }

pub(super) fn receive(&self) -> ArgMatches {
    let command: Command = Receiver::load_command_settings();
    command.get_matches()
}

fn load_command_settings() -> Command {
    Command::new("rast")
        .about("AST Based Language")
        .author("shunsock")
        .version("0.1.0")
        .arg(Arg::new("expression").required(false).short('e'))
        .arg(Arg::new("file").required(false).short('f'))
        .arg(
            Arg::new("debug")
                .short('d')
                .long("debug")
                .action(ArgAction::SetTrue)
                .help("Enable debug mode"),
        )
}

}

自分が使える

すぐに使いたかったので、普段書いている言語から選んだ。選択肢は3つで、気分で決めた。

開発秘話的な


サマータイム(DST: Daylight Saving Time)

GitHubでPublicに公開した後、RedditというSNSで意見を募った。インストールしてくれた人がいて、「コーナーケースでバグあったよ」と教えてくれた。

サマータイム(夏時間)とは、夏季の一定期間に時計を通常の標準時より1時間進める制度です。これにより、夕方の明るい時間を有効活用し、エネルギーの節約や生活の質の向上を図ることが目的とされています。

サマータイムの開始時(春)

サマータイムの終了時(秋)

サマータイム開始時(春に時計を1時間進めるとき)

サマータイム終了時(秋に時計を1時間戻すとき)

サマータイム対応

タイムゾーンの変換は、ChronoChrono Tzというライブラリを使っている。このライブラリでは、タイムゾーンの変換が一対一でないことを前提に、 Single, Ambiguous , None という計算結果の値を用意している。

Timezone Translatorでもこの実装を採用し、エラーハンドリングを行っている

pub(crate) fn convert(&self) -> Result<DateTime, TranslationError> {

let mapped: MappedLocalTime<DateTime<Tz>> = self.from_tz.from_local_datetime(&self.time);

match mapped {
    LocalResult::Single(time) => Ok(time.with_timezone(&self.to_tz)),
    LocalResult::Ambiguous(time_earliest, time_latest) => {
        Ok(select_time_with_ambiguous_time_strategy(
            self.ambiguous_time_strategy,
            self.to_tz,
            time_earliest,
            time_latest,
        ))
    }
    LocalResult::None => {
        let error = TranslationError::TranslationError {
            time: self.time,
            from_tz: self.from_tz,
            to_tz: self.to_tz,
        };
        Err(error)
    }
}

}

github.com

タイムゾーンが入力されていないときの挙動

タイムゾーンの入力がめんどくさい人むけに時間の自動入力をサポートしています。主に自分。

pub(crate) fn command_provider() -> Command { let now: String = provide_local_timezone_string(); let now_str: &'static str = Box::leak(now.into_boxed_str());

Command::new("tzt - Timezone Translator")
    .version("0.3.0")
    .author("shunsock")
    .about("translate time from one timezone to another")
    .arg(time())
    .arg(from(now_str))
    .arg(to(now_str))
    .arg(ambiguous_time_strategy())

}

変数を渡すことでデフォルトの値を設定している。

use clap::Arg;

pub(crate) fn from(timezone: &'static str) -> Arg { Arg::new("from_timezone") .short('f') .long("from") .value_name("FROM_TIMEZONE") .help("The original timezone (e.g. America/New_York) @see https://docs.rs/chrono-tz/latest/chrono_tz/enum.Tz.html") .required(false) .default_value(timezone) }

実は、この機能気合いでやっていたりします。環境変数を見たり、システムのタイムゾーンのファイルを見に行ったりします。

pub(crate) fn provide_local_timezone_string() -> String {

let env_var_tz: Option<String> = EnvironmentVariableTzProvider::new(None).get_env_var_tz();
if let Some(env_var_tz) = env_var_tz {
    return env_var_tz;
}


let tz_from_etc_localtime: Option<String> = get_system_timezone_from_etc_localtime();
if let Some(tz_from_etc_localtime) = tz_from_etc_localtime {
    return tz_from_etc_localtime;
}


let tz_from_etc_timezone: Option<String> = get_system_timezone_from_etc_timezone();
if let Some(tz_from_etc_timezone) = tz_from_etc_timezone {
    return tz_from_etc_timezone;
}

let error_message = "System Timezone Not Found:
Could not find local timezone. Please set TZ environment variable.
";
panic!("{}", error_message);

}

https://github.com/shunsock/timezone_translator/blob/main/src/infrastructure/current_local_timezone_provider/local_timezone_string_provider.rs

まとめ

参考にしている本とか

Rustのプログラミングは公式ドキュメントとこの本で学びました。

amzn.to

途中でプログラミング言語の話が出てきたので、こちらも載せておきます。

amzn.to

JavaとCですが、参考になると思います。

amzn.to

私は趣味でCLI職人をしているのですが、ある日気づきました。 「業務上、標準関数を自分でいじれるプログラミング言語、一つぐらいあったほうが便利じゃね?」

で、作りました。

let main: fn = (x: string): None { let message: string = "Hello, " + x; print(message); return none; };

main("Shunsock");

print関数も開発段階なので、まだ型名が出ています。味があっていいですね。

shunsuke.tsuchiya in ~/Hobby/rast on function λ rast -f tests/data/function.rast Str("Hello, Shunsock")

言語開発をしようとするとデバッグが面倒になってくるので、デバッグオプションを差し込んでいます。

shunsuke.tsuchiya in ~/Hobby/rast on function λ rast -f tests/data/function.rast -d Scanned Tokens: Let Identifier("main") Colon Fn Equal LeftParen Identifier("x") Colon StringType RightParen Colon NoneType LeftBrace Let Identifier("message") Colon StringType Equal StringLiteral("Hello, World!") Plus Identifier("x") Semicolon Print LeftParen Identifier("message") RightParen Semicolon Return NoneLiteral Semicolon RightBrace Semicolon Identifier("main") LeftParen StringLiteral("shunsock") RightParen Semicolon Eof

AST is created: AST[0]: Statement(FunctionDeclaration(FunctionDeclarationNode { name: "main", params: [("x", "string")], return_type: "none", body: [Statement(VariableDeclaration(VariableDeclarationNode { name: "message", var_type: "string", value: BinaryOperation(BinaryOperationNode { left: Literal(LiteralNode { value: String("Hello, World!") }), operator: "+", right: Identifier(IdentifierNode { name: "x" }) }) })), Statement(Print(PrintNode { expression: Identifier(IdentifierNode { name: "message" }) })), Statement(Return(Literal(LiteralNode { value: None })))] })) AST[1]: Expression(FunctionCall(FunctionCallNode { name: "main", arguments: [Literal(LiteralNode { value: String("shunsock") })] }))

Str("Hello, World!shunsock")

clapは優秀なAPIを提供してくれるのでこれだけでパースができます。(自分のCLIでは実際には複数ファイルでこれを書いている、詳細は下の方みてくれ)

let cmd = Command::new("rast") .about("AST Based Language") .author("shunsock") .version("0.1.0") .arg(Arg::new("expression").required(false).short('e')) .arg(Arg::new("file").required(false).short('f')) .arg( Arg::new("debug") .short('d') .long("debug") .action(ArgAction::SetTrue) .help("Enable debug mode"), );

let matches = cmd.get_matches();

let debug_mode: bool = matches.get_flag("debug");

明後日に同じような話をする予定ですが、ディレクトリはこんな感じに切るのがおすすめです。

src ├── main.rs # 本体 ├── rast_error.rs ├── receiver.rs # Clapのユーザー入力の実体を送ってくれるやつ ├── source_code_loader.rs # サービス ├── virtual_machine # サービス │   ├── ast.rs │   ├── evaluator │   │   ├── evaluation_error.rs │   │   ├── function_table.rs │   │   ├── symbol_table.rs │   │   └── value.rs │   ├── evaluator.rs │   ├── parser │   │   └── parser_error.rs │   ├── parser.rs │   ├── scanner │   │   └── scanner_error.rs │   ├── scanner.rs │   └── token.rs └── virtual_machine.rs

5 directories, 16 files

ここはウェブ開発とかだとModel, Router, Controller, Service, Repositoryなどで一段階切っちゃうパターンが多いかもですね。(どれを使うかは人や組織によるだろう) 今回の場合、ソースコードをOnelinerで入力するパターンとプログラムから読み込ませるパターンにデバッグオプションが付くだけで最終的にはどれもvirtual_machineというプログラムに行き着くため、サービス直置きって感じです。

とはいえ、インタープリタをそのまま一つのファイルに書くと世界が崩壊するので、feature in featureしています。具体的にはScannerとParserとEvaluatorです。それぞれ500 line - 1000 line位はあるので、もっと分割した方が良い説が濃厚かなという気持ちです。次の実装するとしたら標準関数なのですが、Evaluatorが相当膨れているので、その前にリファクタリング作業に追われることになるでしょう。今見るとASTはvirtual_machine直置きで、tokenがscannerなの謎ですね。Parserでも呼ばれるので場所変えようかな。

公開は当分先です。まだ、開発中ってことで。

ではまた。

入社から少し経って、近況を聞かれることも増えてきたので報告。

Q&A

概要

8月16日付けでファインディ株式会社に入社しました。現職では、データエンジニアとして、CTO室データソリューションチームに所属いたします。

転職情報

期間

4月の半ばぐらいに転職の意思決定をして、5月末に終了しました。

データに関わるエンジニアとして、チームで働くことのできる企業に行きたいと考えていました。また、組織横断的なチームに所属したいと考えていました。

軸ではない

逆に、下記の事項は気にしませんでした。

  1. 技術スタック: 好きな技術は「勝手に触ってしまう」ので気にしてもなあ
  2. 年収アップ: Roleが上がるタイミングではないので、気にしていませんでした。

経緯

いわゆるリファラルです。

  1. 技術系カンファレンスでCTO&DevRelチームとお好み焼きを食べた
  2. 友人が新卒で入社
  3. 転職しようかなと考えていた矢先、ファインディがデータエンジニアの募集をしていることを知り、友人に連絡
  4. カジュアル面談、選考
  5. 内定承諾

面接対策

Xで話題になっていたので、読みました。聞かれた部分は読む前から知っていたので、就活に寄与したかは謎。全く関係ないけれど、友人のソフトウェアの相談で、中盤から後半あたりに載っていた方法が役にたちました。趣味で読んでも面白いんじゃないかなと思います。

アレックス・シュウ."システム設計の面接試験".2023.ソシム

変わることと変わらないこと

所属は変わりますが、エンジニアとしてこれからも働きます。技術イベントが好きなので、変わらず、登壇・聴講に行く予定です。

ファインディはRubyでアプリケーションが動いているので、Rubyのイベントにも行ってみようかなーと思っています。

これからもよろしくお願いします!

かなり暗い話です.事実をまとめます.

4歳からクラシック音楽を子供の頃から学んでいたのですが,技術力が足りず,高二の秋で諦めました.最後の方は精神を病んでしまい,脅迫性障害になっていました.最近落ち着いたのですが,通院を6-7年しています.ちなみに,進学は現役で藝大行くことが条件でした.浪人前提だと思われがちですが,藝大は3割ぐらいが現役で入れます.

中高生の頃に染み付いてしまった夜型のせいで,家族と生活リズムがあまりにも合わず,互いに辛かったので,一人暮らしをしています.ただ,子供の頃に受けた恩を少しずつでも返したいなと思っていて,実家に差し入れ持って行ったりご飯誘ったりしています.この行動にはここ数年で,世話になった方が次々に亡くなってショックを受けた背景があります.

プログラミングはB2の時に始めました.マーケティング学科という名前の統計応用学科だったからか,理工系の教授に師事することになり,科学計算をするために学びました.子曰く,「プログラミングと大学数学は独学で学べ」らしいです.なので,プレゼンの論理の穴を突かれたことはあっても,何かを習ったという経験は実はなかったりします.

師というか,大学では特に以下のことを叩き込まれました.今思えば,貴重な学びですね.

数学も,※ 高校まではパズルみたいでつまらないなーと思っていたのですが,大学で基礎に触れて面白いなと思うようになり,本を漁るようになりました.分野で言うと統計的言語モデルに興味があります.最近は,数理力を上げるために「現代数理統計学の基礎」という本を周回演習しています.

※ 主観です.同様の理由で競プロなども続かなかったです …

いわゆるWebのプログラミングを始めたのは,Pythonを使って生活をハックしようと思ったことがきっかけでした.当時コロナ禍で,リアル麻雀が打てなくなったのでライブ感がなく寂しく感じていました.そこでライングループ用にWebhookを開発したりしました.そこから,インターンに行ったり,ハッカソンに出るようになって今に至ります.

統計計算がメインだったので,Web系に来てからは知識面で苦労しましたが,カンファレンスや勉強会が毎月開催される環境だったので,比較的容易にキャッチアップできました.YAPC::Kyoto 2023がきっかけでオフラインの会に出るようになったので,誘っていただいたuzullaさんとcatatsuyさんに感謝しています.

業務・趣味ではCLIを開発していることが多いです.趣味だとRustを書いている時間が長くなりましたが,仕事にするつもりはあまりなかったりします.最近,Rubyを始めました.Sorbetという静的解析ツールが快適で今のところ楽しいです.

振り返ると,今も昔も何か作るのが好きだったんですね.子供の頃は親のWindows Vistaのプリントミュージックで作編曲に没頭していましたし,今も相変わらず土日家に引きこもってプログラムを書いています.これからも楽しく何かに没頭して過ごしたいものです.