sontixyou blog

技術まわり、ガジェット関連について

RustでCloudflare workerを使ってみた

背景

Cloudflare workerにRustを使って、アプリケーションを作成できることを聞いたので、ドキュメントに沿ってトライしたいと思った。

そこで、次のドキュメントをもとに、試しにやってみた。

developers.cloudflare.com

本題

cargo generateというコマンドを作って、雛形を作成する。ここで、自分の指定したいプロジェクト名を入力する。 今回は馴染みがあるaxumを選んだ。

cargo generate cloudflare/workers-rs
⚠️    Favorite `cloudflare/workers-rs` not found in config, using it as a git repository: https://github.com/cloudflare/workers-rs.git
✔ 🤷   Which template should be expanded? · templates/axum
🤷   Project Name: first_rusty_worker
🔧   Destination: /Users/kengo/projects/rust-projects/first_rusty_worker ...
🔧   project-name: first_rusty_worker ...
🔧   Generating template ...
🔧   Moving generated files into: `/Users/user_name/projects/rust-projects/first_rusty_worker`...
🔧   Initializing a fresh Git repository
✨   Done! New project created /Users/user_name/projects/rust-projects/first_rusty_worker

すると、first_rusty_workerというディレクトリが作られて、その中にいくつかのファイルが作成される。

npx wrangler devをやると、ビルドが始まり、webassemblyへコンパイルされると思った。

しかし、コンパイルエラーが出た。worker-rs crateのバージョン下げたりしたが、解決できなそうなのでissueに切ることにした。

github.com

いくつかアドバイスをもらったおかげで、コンパイルできるところまではできた。

次やること

worker-rs crateに対して、なにかしらの修正・改修をしないと行けない感じがするので、対応したいなぁ

Rustでの成長記録:Rust製のcatコマンドを作ってみた

背景

最近、Rustを学び始めた。 次の目的でCLIを作ろうと思った

  • Rustを書くスキル向上
  • Rustらしくコードを書けるようになりたい
  • 普段、使っているCLIを作ってみたい。

なにをつくったの?

catコマンドをRustで作った。その名は、soncat(呼び名はソンキャット)

github.com

sontixyousoncatをつなげたもの。 catsとかscatを思いついたが、微妙な気がしたので、ボツ。

使い方はこんな感じ。フラグを指定をすることで、行数を表示することもできます。

> soncat hello.txt
hello soncat

goodbye soncat

> soncat hello.txt -n
     1  hello soncat
     2
     3  goodbye soncat


 ❯ soncat hello.txt -b
     1  hello soncat

     2  goodbye soncat

初めて知ったこと

  • println!("{line_number:6}\t{line}");これで、行番号であるline_numbersを右寄せ6文字幅で表示することができる。とんがりだと中央寄せ。

Goodなこと

  • clap crateの扱いに慣れてきた。
  • Boxやユニット型について、知ることができた。

参考した本

www.oreilly.com

Rustでの成長記録:Rust製のechoコマンドを作ってみた

背景

最近、Rustを学び始めた。 次の目的でCLIを作ろうと思った

  • Rustを書くスキル向上
  • Rustらしくコードを書けるようになりたい
  • GitHub Releaseを使って、自家製ツールを公開してみたい

なにをつくったの?

echoコマンドをRustで作った。その名は、secho(呼び名セコー?でいいかも)

github.com

sontixyouの頭文字sとechoをつなげたもの。

使い方はこんな感じ。オリジナルのechoコマンドと同じ挙動なはず。。。

> secho Hello Rust
Hello Rust

伸びしろ

  • Macでしか使えません。ほかのOSで実行する欲がないため。
  • developブランチからmainブランチへの反映を自動化したい
  • インストール方法がいまいち。Homebrew経由でインストールできるようにしたいなぁ

参考した本

www.oreilly.com

苦労したもの

  • 本に記載されているclap crateのメジャーバージョンと最新版のバージョンと違ったので、本のコードと最新版のclapのドキュメントを照らし合わせることに苦労した

GitHubのデフォルトブランチをdevelopにする方法

前提

GitHubリポジトリを作成した時点では、デフォルトのリポジトリはmainになっている。

やりたいこと

デフォルトのリポジトリをdevelopブランチへ変更する方法を残しておく。

手順

  • まずは、ローカルPCでdevelopブランチを作成する
    • git switch -c develop
  • リモートブランチへプッシュ
  • GitHubリポジトリ > Settings > GeneralにあるDefault branchの設定をdevelopへ切り替える

GitHubの設定ページ

awaitとawait?について

tokio crateを使って、非同期処理を書きたい場合、ほぼほぼasync await構文を書くと思う。 私は、awaitとawait?の違い、使い分けがいまいちわからないでの、頭の整理がてら書いていく。

await

awaitは、非同期関数の結果を待つ。async関数やブロックから呼び出され、

非同期で処理が完了するまで実行を停止します。これにより、他のタスクが並行して実行されることが可能になります。

また、エラーが発生時は、自分でエラーをハンドリングする必要がある。

だが、await?より細かいエラーをハンドリングできそうな印象あるが、コード量は少し増える。

#[tokio::main]
async fn main() {
    let result = some_async_function().await;
    println!("Result: {:?}", result);
}

async fn some_async_function() -> u32 {
    42
}

いい例なのかはわからん。

use reqwest::Error;

#[tokio::main]
async fn main() -> Result<(), Option<Error>> {
    let response = make_request("https://xjsonplaceholder.typicode.com/posts/1").await?;
    println!("Response: {:?}", response);
    Ok(())
}

async fn make_request(url: &str) -> Result<String, Option<Error>> {
    let response = reqwest::get(url).await;
    match response {
        Ok(response) => {
            // レスポンスのステータスコードをチェックし、エラーハンドリング
            if response.status().is_success() {
                let body = response.text().await?;
                Ok(body)
            } else {
                // ステータスコードが成功でない場合はエラーを返す
                return Err(response.error_for_status_ref().err());
            }
        }
        Err(e) => Err(Some(e)),
    }
}

await?

非同期関数の完了を待ちつつ、Result型のエラーハンドリングも行います。

エラーが発生した場合には関数を終了し、エラーを呼び出し元に返します。

use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let result = some_async_function().await?;
    println!("Result: {}", &result);
    Ok(())
}

async fn some_async_function() -> Result<u32, Box<dyn Error>> {
    Ok(42)
}

ほかの事例だとこんな例

use reqwest::Error;

#[tokio::main]
async fn main() -> Result<(), Option<Error>> {
    let response = make_request("https://xjsonplaceholder.typicode.com/posts/1").await?;
    println!("Response: {:?}", response);
    Ok(())
}

async fn make_request(url: &str) -> Result<String, Option<Error>> {
    let response = reqwest::get(url).await?;

    // レスポンスのステータスコードをチェックし、エラーハンドリング
   // ここでresponseがエラーかを判断するにはstatusコードを確認する。
    if response.status().is_success() {
        let body = response.text().await?;
        Ok(body)
    } else {
        // ステータスコードが成功でない場合はエラーを返す
        return Err(response.error_for_status_ref().err());
    }
}

axumで作ったAPIのテストを書く際にハマった話

背景

2024/6あたりにRustでWebアプリ作れたら、面白いかもと思い、フレームワークなんなりを探していた。

そんな中で、axum(アクサム)を見つけた。Youtubeの外国人が、アクサムと言っていたので、たぶん日本語読みはアクサムが正しい。

github.com

このaxumを使って、APIを試しに作った。そのときに、実装コードを書くだけではつまらないので、テストコードも書くことにした。

しかし、テストコードを書くときに2〜3時間くらい、どんな感じでテストを書けば良いのかわからず、ハマったので記録として残しておく。

問題

普段、私はGitHubを使って、コード管理している。

そのため、ローカル環境とGitHub ActionsのCI両方で、テストをパスする必要が出てくる。

ひよっこRustaceanのわたしは、次のようなテストコードを書いていた。

このテストコードを実行すると、ローカル環境ではパスするが、GitHub Actions上ではパスしない。

GitHub Actions上でサーバーを起動しっぱなしになるようで、テストの実行が完了するが、サーバーが起動しつづけているので、ワークフローが完了しない。

// main.rs
// 良くない例

use axum::{
    routing::get,
    Router,
};

#[tokio::main]
async fn main() {
    // build our application with a single route
    let app = Router::new().route("/", get(|| async { "Hello, World!" }));

    // run our app with hyper, listening globally on port 3000
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

mod tests {
    use reqwest::StatusCode;
    use std::process::Command;

    #[test]
    fn test_hello_world() {
        Command::new("cargo").arg("run").output().unwrap();

        let client = reqwest::blocking::Client::new();
        let response = client.get("http://0.0.0.0:3000/").send().unwrap();

        assert_eq!(response.status(), StatusCode::OK);
        let text = response.text().unwrap();
        assert_eq!(text, "Hello, World!");
    }
}

解決

axum-testというcrateを追加することで、axumのモックサーバーを使うことができる。

github.com

axumのリポジトリには、テスト周りの記述がなく、このcrateを探すまでにとても苦労した。

また、axum-testについて紹介しているブログ記事等も少なく感じたので、紹介することにした。

Rustのmoduleとcrate

背景

私は、今までC言語Rubyくらいしかプログミング経験がなかった。 最近、Rustを書き始めたことで、初めましての概念がたくさん出てきたので、頭の整理がてらまとめる。

ここに書く内容は、Rust Programming Languageの原文を読んだことのまとめである。

doc.rust-lang.org

module

moduleには2種類ある。パブリックかプライベートかの2種類。

先頭にmodがつくかつかないかの違いだけ。

moduleはネストできるし、関数を中に定義することも可能。

crate

Rustには2種類のcrateがある。

  • binary crate
  • library crate

binary crate

これはbinary crate。

各クレートには、実行ファイルが実行されたときに何が起こるかを定義するmainと呼ばれる関数を持つ必要がある。

// main.rs
fn main {
  println!('hello rust');
}

library crate

main関数を持たず、複数のプロジェクトで供することを目的として機能、関数を指す

これはlibrary crate

// number_calculator.rs
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

package

単数または複数のcrateを束ねたものがpackage

基本的に、cargo.tomlに書いてあるnameはpackage

関係でいうと、package has many crates or one crate.

crate has many modules or one module.という感じ。

全体のイメージはこんな感じ。

github.com

RubyKaigiに行ってくる

去年に引き続き、RubyKaigi2024に行く。

セッションを聞くことにも重視したいが、他にも重視したいことがある。 書き出すとこんな感じ。要はできるだけ多くのRubyistと話して、交流したい。

  • 国内にいながら海外のエンジニアさんとも交流できる貴重な機会であるため、普段どのように開発しているのか等の情報を交換したい。
  • 海外カンファレンスとどういったことが違うのかや世界でのRuby,Railsの立場とかについて、Web業界で働いてるエンジニアさんの生の声や考えを知りたい
  • 技術、開発プロセス、普段活用しているgem周りについても意見交換したりしたい。

身の回りのRust

背景

2023~2024年の3月にかけて、自分の身の回りでRustで作られているツールが増えていると感じている。
自分が使っているツールの中でもRustで作られているものがある。これらのツールをまとめたことがなかったため、まとめる。

身の回りのRust

Ruby

RubyはJust-In-Time(JITコンパイラという機能を備えており、その中でもYJITがRustによって実装されている。

CLI

lsコマンド

今までは、Mac標準のlsコマンドを使用していた。そこから、lsdへ切り替えた。

github.com

grepコマンド

今までは、Mac標準のgrepコマンドを使用していた。そこから、ripgrepへ切り替えた。

標準のgrepコマンドより高速に動くので、とてもいい。また、Neovimで使用しているプラグインでも活用しているため、このツールは欠かせない。

github.com

ターミナルエミュレーター

私は、2年前ほどからweztermというターミナルエミュレーターを使用しています。 weztermは日本語を正常に入力できて、表示できるのでとても良いです。

github.com

プロンプト

シェルのプロンプトをカスタマイズするものとして、starshipを使用しています。

github.com

最後に

仕事で使っている言語からツールまでの各所で、私はRustのお世話になっていました。こんな状態なので、そろそろRustを使えるようになる必要があるのかなぁと考えたりしています。

Active Recordのカラムの暗号化でソートできずにハマった

背景

記事のタイトルを保存するtitleカラムがあるとします。このtitleカラムは、記事一覧ページでtitleの並び替え機能があるとします。
あるとき、Railsで文字列を保存するtitleカラムを暗号化しようと話題が出ました。

カラムの暗号化

Railsには、2種類の暗号化が用意されています。

カラムを並び替えしたい

以下のレコードをencrypted_titleカラムを指定して、並び替えしたいとします。

mysql> select id, encrypted_title, title from posts;
+----+--------------------------------------------------------------------------------------------+---------+
| id | encrypted_title                                                                          | titile |
+----+--------------------------------------------------------------------------------------------+---------+
| 38 | {"p":"PCAd","h":{"iv":"0/OwqRAVpqf4HXBP","at":"CgzTlnJnc89XS+alEZ3G7Q=="}}                 | 123     |
| 46 | {"p":"PCAd","h":{"iv":"0/OwqRAVpqf4HZGE","at":"CgzTlnJnc89XS+alEZ3G7Q=="}}                 | あかさたな     |
| 47 | {"p":"PCAd","h":{"iv":"0/OwqRAVpqf4HABC","at":"CgzTlnJnc89XS+alEZ3G7Q=="}}                 | 一覧     |
| 48 | {"p":"PCAd","h":{"iv":"0/OwqRAVpqf4HABC","at":"CgzTlnJnc89XS+alEZ3G7Q=="}}                 | 一蘭     |
+----+--------------------------------------------------------------------------------------------+---------+

普段なら、次のようなコードで並び替えをします。

Post.all.order(encrypted_title: :desc) # titleカラムを降順で並び替えた結果と同じになってほしい。

このコードを実行しても、titleカラムを降順で並び替えた結果と同じにはなりません。
なぜなら、encrypted_titleの暗号化された文字列で並び替えをされてしまうため。上のコードを実行したタイミングでは、encrypted_titileは復号化されていません。。。

並び替えするには。。。

次のようなコードを実行する必要があります。自分が求めている並び替えをSQLでできないため、Rubyの世界で並び替えをやります。

Post.all.sort_by { |p| p.encrypted_title }

しかし、この手法にはパフォーマンス悪化の懸念があります。 例えば、postsテーブルに10万件レコードあるとき、Rubyの世界での並び替えはSQLでの並び替えより速度が劣るはず。
なので、どうしようもないときの最終手段で用いたほうがいいと考えています。

最後に

今までカラムの暗号化するのは、センシティブな情報を含むパスワード等しかやったことがなかったです。
今回の事例で暗号化の理解や並び替えについての知識を身につけられたのはよかよかです!

Neovimにtypoを検知する仕組みを追加した

背景

Neovimには、デフォルトでスペルチェックする機能があります。
しかし、このスペルチェックはマークダウンファイルに対しては有効ですが、コード内の英単語をチェックしてくれません。
そこでコード内の英単語もスペルチェックしてくれる仕組みを導入することにしました。

typoを検知する仕組みをどうやるか調査

Neovimで使用できるプラグインを探すところからです。
私が探した結果は選択肢は2つありました。

① 次のプラグインを導入すること github.com

② LSPを利用して、typoを検知する ※ LSPの設定が必要 github.com

私のNeovimの設定では、Masonプラグインを既に利用していました。 さらに、LSPを利用してtypo検知できたほうが作業しやすそうな気がしたので、②を採用しました。

導入

Neovim上で次のコマンドを実行するだけです。

:MasonInstall typos-lsp

ここのページのコマンドを参考にしました。

mason-registry.dev

動作確認

canceledのつづりを間違えると、次のように指摘してくれます。やったぜ🎉

最後に

さらば、すべてのtypoよ!!!!!!

イタリア語の学習を始めた

背景

2024/09にイタリアへ行く予定を立てた。 学習のモチベは、イタリアの現地人の方と簡単なコミュニケーションを取れると、旅も楽しくなると思ったから。

目標

  • レストランで注文できる
    • おすすめの品とか聞けると最高
  • 市場で話しながら買い物できる

どうやって学習するか

YouTubeの以下の動画を見ながら、発音真似ている。 https://m.youtube.com/playlist?list=PLUcDBadaP5IUJYW6qn2jTH0Ik2EMvAPze

一通り見たら、単語を覚えつつ、文章作りたい。 イタリア語で簡単なブログを書きたい。

開発環境ソフト編 2023

2023年で使用していたソフトウェアをずらずら書いていく。

ソフト

ブラウザ

Brave

あらゆる広告を非表示士にしてくれるため、プライベートでは、いつも使っている。 https://brave.com/ja/

ブラウザ拡張機能

GraphQL Network Inspector

https://chromewebstore.google.com/detail/graphql-network-inspector/ndlbedplllcgconngcnfmkadhokfaaln?hl=en-GB&pli=1

普段の開発では、GraphQLを使用している。 Chromeの標準のネットワーク検証機能では、リクエストとレスポンスの中身を見ることが手間だった。 この拡張機能を導入したことで、リクエストとレスポンスの中身を簡単に見ることができるため、作業が捗る。

Wappalyzer

https://chromewebstore.google.com/detail/wappalyzer-technology-pro/gppongmhjkpfnbhagpmjfkannfbllamg

はじめて訪れたサイトでは、どんなフレームワークや言語を使って実装されているのか気になるので、入れている。

エディタ

VSCode

https://code.visualstudio.com/

Github copilot chatを使うための専用機になっている。また、デフォルトの状態である程度使えるかつマークダウンのプレビュー機能があったりと重宝している。

Neovim

https://neovim.io/

普段使うエディタは、Neovim。Vimと違い、デフォルトで言語サーバーと通信する機能等が同梱されているため、LSPを利用したコード補完を設定することが楽。 また、最近は0から設定するのではなく、lazynvimというプラグインを使って、ある程度の設定を自動で行える仕組みが存在する。結構便利。

ターミナルエミュレータ

Wezterm

https://wezfurlong.org/wezterm/index.html

タブ機能が標準でついてるため、特にカスタマイズしなくても使える。 WeztermとNeovimの設定をLuaで書くことができるため、結構好き。 日本語の入力もちゃんとできることもポイント高い。

シェル

https://www.zsh.org/

zshをずっと使っている。コマンドの補完や入力履歴を辿る等のライブラリが豊富であるため、fishやnushellに乗り換えることは考えていない

フォント

SFMono Square

https://github.com/delphinus/homebrew-sfmono-square

このフォントの特徴が2つある。

  1. 半角2文字の幅と全角1文字の幅が等しく、表示される。
  2. 全角スペースが◯として表示される。コード内に全角スペースがある場合、すぐに気づく事ができる

また、Nerd Fontsに対応しているため、特殊な記号やアイコンも表示できる。

カラースキーム

One Dark

https://github.com/one-dark

基本的にダーク系のカラースキームを好んで使う。 onedarkを2年くらい続けている。 時々、カラースキームを変える場合は、capputinoに切り替えることが多い

https://github.com/catppuccin

2024年の目標

2024年の目標を決めていく〜

2023年の振り返りはこちらを参照 → https://sontixyou.com/entry/2023/12/21/215413

日頃仕事していると自分のスキルをもっと上げて、プロダクト開発へ活かしていきたいと痛感する一年でもあった。なので、そのあたりを深掘りながら、来年の目標を決めていきたい。

自分のスキルを上げるために

以下のあたりがもっと欲しいスキルであったりする。

  • システムの設計力
  • 仕様を把握できる力
  • 素早く実装できる力
  • 自分が関わるプロダクトのドメイン知識を増やしたい

これらの4つのスキルを伸ばしていくためには、どんなことをやる必要があるのか?

システムの設計力

  • テーブル設計について学ぶ
    • テーブル設計に関する本を読む
    • テーブル設計が必要な開発をたくさん行って、場数を踏む
  • システムアーキテクチャについて学ぶ

仕様を把握できる力

  • 自分とチームがスムーズに仕様を固めて、共通認識を持てるようにリードする力をつける
    • 実例マッピング以外にいい方法がある模索していく - ユーザーのどんな課題をどんな手法で解決していくのか。さらに、それをどうやってシステムへ落とし込んでいくのかを決めていく力をつける
    • 仕様把握を素早く行って、実装するまでの時間を縮める
      • 機能の設計から関わるまたは機能を実装途中から合流する場合も含む

素早く実装できる力

  • RailsRubyの知識をたくさん吸収しつつ、アウトプットする
    • Railsガイドを定期的に読み返す
    • なにかしらの自作ライブラリを1つ以上作成する。新しい言語に挑戦したい場合、Rubyでなくてもいい。
    • InteractorやServiceなど、Railsを拡張していく部分について知る。そして実践する
  • SQL周りなど実装に必要な知識を足す
    • 複雑なSQL(select, join, groupなどの複合技のパターン)をスラスラ読めるようになる
      • 読むことに時間がかかるため
  • フロントエンド周りの知識(これは余裕あれば)
    • Reactの記法あたりは読めるようになっておく

自分が関わるプロダクトのドメイン知識を増やす

  • 開発生産性に関する本を読む
    • DevOpsの科学(リピート)
    • etc

スキル以外のこと

旅行編

その他

  • 好きなアーティストのライブ行く
  • 自作キーボードを作る
  • LT登壇する
  • コントリビューション数を10,000 OVERする
  • 吸収した知識や取り組んだことをアウトプットする
    • 2023年の振り返りをやるときに、その年になにをやっていたのか辿るのが大変だった

2023年の振り返り

2023年の月ごとの振り返り

1月

shibuya.rbに初参加! RubyKaigi 2022へ行って以来、Rubyコミュニティに参加できていなかったため。

2月

https://regional.rubykaigi.org/fukuoka03/

RubyKaigi 2022以来、でかいカンファレンスに参加できることが楽しみでウキウキ楽しかった。ここでANDPADの方と話して、転職しよと決断した。

3月

転職活動をメインにやっていた。働きながら、転職活動をするのは大変だった。しかし、前回の転職時も同じよう感じだったので、そこまで苦ではなかった。

4月

転職先が決まったので、そのときに働いている場所での引き継ぎ作業なんやらやっていた。

5月

ファインディ株式会社へ転職した。

GW開けに、RubyKaigi2023へ参加した。昨年、会ったRubyistや福岡でお会いした方とも再開できて、うれしみ。

また、コロナ明けで通常営業のRubyKaigiであったため、大規模であったし、Drinkupも最高だった。

新しい技術とプロダクトキャッチアップがとても大変な月だった。これは、9月くらいまで続く。がんばった、わし偉い。

6月

2回目のshibuya.rbに参加した。

人生で初LT登壇した。Neovimについて話した。初めてにしては、よくできたんでは?と思っている。

https://findy.connpass.com/event/283154/

7月

コロナがだいぶ落ち着いたこともあって、本格的に旅行したい気持ちが強くなったので、旅行リハビリがてら台湾へ2泊3日行ってきた。 台湾は5年ぶり2回目だが、とても楽しめた。

8月

仕事に忙殺かつお盆もあり、旅行は行かなかった。

9月

メタルギアコンサートが開催されると聞いて、参加してきた。 とても大満足なコンサートであった。

10月

仕事に忙殺されながら、月末に感染性大腸炎になって大変だった。 人生初MRIや直腸検査、内視鏡検査など自分が知らない世界を多く体験した付きだった。

なんとか回復したので、月末からイギリス旅行に行った。初の英語圏の国で乗り継ぎもはじめてで、終始楽しい旅であった。機会作って、また行きたい。次回は健康体でパブでビールをがぶがぶ飲みたい。

11月

私が携わっているFindy Team+がRuby Bizグランプリに受賞したため、その表彰式のために島根へ行ってきた。初島根だった。

さらに、表彰式の翌日はRubyWorldConferenceが開催されるため、そちらも参加してきた。RubyKaigiでは会えないような企業の方と会うことができて、とても良かった。

12月

VSCodeをメインに使ってきたが、Neovimへまたカムバックした。 VSCodeで使用していた拡張機能が安定していなかったため、Neovimへカムバックした背景がある。

2023年に決めた目標の進捗度合い

5月にRubyKaigiへ参加した後に、2つの目標を立てた。これらの進捗を振り返ってみよう

  • 英語力の底上げ 特にスピーキング
  • OSSコントリビュート
    • 目指せ5個

英語力の底上げ

正直な話、あまりできていない。イギリスへ旅行したときに、あまり意思疎通できていなかったため、とても悔しい思いをしたので、もっと底上げできるようにしたい

OSSコントリビュート

こっちは、進捗あった。7件PRがマージされたので、よしよしだと思う。 ほとんど、ドキュメント修正だったが、1件だけコード修正したものがあった。それが一番上にあるPR。普段使っているNeovimプラグインに対して、貢献できたのは自分の中では、とても大きいこと!偉い

https://github.com/nvim-pack/nvim-spectre/pull/192

https://github.com/yytypescript/book/pull/756

https://github.com/railsgirls-jp/railsgirls.jp/pull/694

https://github.com/railsgirls-jp/railsgirls.jp/pull/677

https://github.com/railsgirls-jp/railsgirls.jp/pull/703

https://github.com/railsgirls-jp/railsgirls.jp/pull/706

https://github.com/virtualshield/rails-graphql/pull/28

https://github.com/zed-industries/community/issues/1701

最後に

2023年は、転職したり、OSSコントリビュートや海外旅行など楽しい一年だった。 だけど、日頃仕事していると自分のスキルをもっと上げて、プロダクト開発へ活かしていきたいと痛感する一年でもあった。なので、そのあたりを深掘りながら、来年の目標を決めていきたい。