Toyokumo Tech Blog

トヨクモ株式会社の開発本部のブログです。

プリントクリエイターに縦書き機能を実装しました

こんばんは。開発本部の石川です。 今回は、弊社のkintone連携製品の一つであるプリントクリエイターに「縦書き出力機能」*1*2を追加した軌跡を備忘録として書き残しておこうと思います。

  • プリントクリエイターとは
  • 縦書きに対応したライブラリが無い問題
  • 縦書きを実現する方法の検討
    • TCPDF改造案 -> ボツ
      • 文字列の描画方向を変更する
      • 縦書き用の記号を利用するように
      • 非埋め込みフォントで縦書きする
      • 縦書き用TCPDF独自フォントデータを作成する
    • 文字列を1文字ずつ分割して縦に並べる -> 採用
  • まとめ

プリントクリエイターとは

サイボウズ社が提供するkintoneに連携するWebサービスで、kintoneに保存されたレコード情報*3からワンクリックでPDF(帳票)を出力する機能を提供しています。

文字列の印字は勿論、画像/バーコードの印字や宛名ラベル形式での出力など、kintoneの印刷機能を強力にサポートする便利な機能をシンプルな操作で利用することができる製品です*4

しかし、日本語では当たり前に行っている「文字を縦に書く」ということに、プリントクリエイターは長年対応していませんでした。 はがきや名刺など、日本語の場合は「縦に書きたい」と思う事がある……というのは勿論把握していましたが、後述する技術的問題から長期間実装を見送っていました。

*1:【帳票作成】プリントクリエイターで縦書き出力ができるようになりました!

*2:プリントクリエイターが待望の縦書きに対応しました!

*3:kintoneはデータベースのようなもので、自由にアプリを作成することができ、それぞれのアプリにレコードとして情報を格納することができます。参考

*4:【kintoneから直接帳票作成】プリントクリエイターとは?

続きを読む

モノレポなClojureプロジェクトをClojure LSPで開発するための設定方法

こんにちは。開発本部の木下です。

Visual Studio Codeの普及と同じくしてLSP(Language Server Protocol)を開発で使用することは普通のこととして浸透したように思います。

LSP があれば、Intellij IDEAに代表される IDE が提供してきたような開発体験を VSCode や Vim や Emacs といった普段から自分が使用しているエディタで得られることができるようになります。

しかしながら弊社の Clojure アプリケーションで LSP を使った開発を生産的に行うには 1 つ問題がありました。 この記事ではどういった問題なのかということと、その解決策について記載します。

これまでの構成

弊社のプロジェクトは基本的に次のように 1 つのリポジトリ(プロジェクト)に複数のモジュールが存在する、いわゆるモノレポな構成になっていました。

.
├── .clj-kondo
├── .cljstyle
├── Makefile
├── api1
│   ├── deps.edn
│   ├── src
│   └── target
│       └── api1.jar # api1 としてデプロイ
├── api2
│   ├── deps.edn
│   ├── src
│   └── target
│       └── api2.jar # api2 としてデプロイ
└── common
    ├── deps.edn
    └── src

上記の例では、common, api1, api2 の 3 つのモジュールがあります。 共有したいコードは common に配置し、api1 と api2 は独立したアプリケーションとしてデプロイします。

api1 と api2 からは:local/rootを利用して common を参照します。

;; api1/deps.edn or api2/deps.edn
{:deps {myproject/common {:local/root "../common"}}}

この構成において注意したいのは common モジュールのコードを変更する時です。

通常の開発時は api1 や api2 の REPL を起動して開発することになりますが、 common にある関数を変更する際は、それを呼び出している箇所を api1 と api2 を横断して確認する必要があります。

LSP で開発するときの問題点

このようなプロジェクトをClojure LSPを使って開発してみるとします。

ここで考えなければいけないのは、どこを LSP にとってのプロジェクトルートとするかです。 以下の例で考えてみます。

.
├── .clj-kondo
├── .cljstyle
├── .lsp --------------------------(1)
├── Makefile
├── api1
│   ├── .lsp ----------------------(2)
│   ├── deps.edn
│   ├── src
│   └── target
│       └── api1.jar # api1 としてデプロイ
├── api2
│   ├── .lsp ----------------------(3)
│   ├── deps.edn
│   ├── src
│   └── target
│       └── api2.jar # api2 としてデプロイ
└── common
    ├── deps.edn
    └── src

(1)はプロジェクトルートを開いて開発するやり方です。 この場合、Clojure LSP が common, api1, api2 を横断して認識してくれることを期待しますが、そうはいかず、開いたファイルしか認識してくれないということが起こります。 これではまともに開発ができません。

(2)と(3)はモジュールごとに開いて(プロジェクトルートとして)開発するやり方です。 例えば api1 を開いた場合、Clojure LSP が:local/root に対応してくれているので common と api1 はうまく認識してくれますが、 common を参照している api2 のコードは認識できません。 この状況のまま開発するとうっかり api2 のことを忘れて common を変更してしまったということが起こりやすくなります。 もちろん注意して検索して探せば参照している箇所を見つけることはできるでしょうが、それは生産的な開発環境とは言えないでしょう。

なぜこのような問題が発生してしまうのかというと、Clojure LSP はクラスパスから情報を得ているためです。 そこで全てのモジュールがクラスパスに入るような解決策を考えます。

解決策 1: LSP のための deps.edn を用意する

解決策の 1 つ目はプロジェクトのルートディレクトリに LSP のための deps.edn を用意するというものです。

.
├── .clj-kondo
├── .cljstyle
├── .lsp
├── deps.edn # 追加
├── Makefile
├── api1
├── api2
└── common
;; deps.edn
{:deps {myproject/common {:local/root "common"}
        myproject/api1 {:local/root "api1"}
        myproject/api2 {:local/root "api2"}}}

このような deps.edn を用意することで、ルートから見ると全てのモジュールがクラスパスに含まれているため、モジュールを横断した参照が可能になります。

解決策 2: 1 つのモジュールにまとめる

解決策の 2 つ目はプロジェクトの構成を変更して 1 つのモジュールにまとめるやり方です。

2.1 ソースコードを src にまとめる

まずはソースコードを全て src 下にまとめるシンプルなやり方です。

次のように配置し、deps.edn にビルドするための設定を追加します。今回はubedrdepsを使っています。

.
├── .clj-kondo
├── .cljstyle
├── .lsp
├── deps.edn
└── src
    └── myproject
        ├── api1
        │   └── core.clj # api1 のメインクラス
        ├── api2
        │   └── core.clj # api2 のメインクラス
        └── common
        │   └── util.clj
{:paths ["src" "classes"]
 :deps {org.clojure/clojure {:mvn/version "1.11.1"}}
 :aliases {:dev {:extra-paths ["test"]}
           :uberjar {:replace-deps {uberdeps/uberdeps {:mvn/version "1.1.1"}}
                     :replace-paths []
                     :main-opts ["-m" "uberdeps.uberjar"]}}}

次のようにビルドします。

mkdir classes
clojure -M -e "(compile 'myproject.api1.core)"
clojure -M:uberjar --main-class myproject.api1.core --target target/api1.jar
clojure -M -e "(compile 'myproject.api2.core)"
clojure -M:uberjar --main-class myproject.api2.core --target target/api2.jar

2.2 モジュールごとにソースを分ける

依存するライブラリを api1 と api2 とで分けたいとなってきたら、alias を使って分離します。

.
├── Makefile
├── deps.edn
├── src
│   └── myproject
│       └── common
│           └── util.clj
├── src-api1
│   └── myproject
│       └── api1
│           └── core.clj
└── src-api2
    └── myproject
        └── api2
            └── core.clj
;; deps.edn
{:paths ["src" "classes"]
 :deps {org.clojure/clojure {:mvn/version "1.11.1"}}
 :aliases {:dev {:extra-paths ["test"]}
           :api1 {:extra-paths ["src-api1"]
                  :extra-deps {}}
           :api2 {:extra-paths ["src-api2"]
                  :extra-deps {}}
           :uberjar {:replace-deps {uberdeps/uberdeps {:mvn/version "1.1.1"}}
                     :replace-paths []
                     :main-opts ["-m" "uberdeps.uberjar"]}}}

この場合は次のようにビルドします。

mkdir classes
clojure -M:api1 -e "(compile 'myproject.api1.core)"
clojure -M:uberjar --main-class myproject.api1.core --target target/api1.jar
clojure -M:api2 -e "(compile 'myproject.api2.core)"
clojure -M:uberjar --main-class myproject.api2.core --target target/api2.jar

ただしこのようにした際は、.lsp/config.edn を用意して alias を LSP に認識させる必要があります。

;; .lsp/config.edn
{:source-aliases #{:dev :test :api1 :api2}}

まとめ

弊社ではこれまで Clojure 開発にCursiveや、弊社の@liquidz作のvim-icedを使うことがほとんどでそれらに最適化されたプロジェクト構成をしていました。

Cursive はプロジェクト全体を静的解析した上で参照関係を把握してくれるので特段問題なく開発できていました。 vim-iced は Clojure LSP を使用せず、clj-kondoを直接利用してプロジェクト全体を静的解析するので問題なく開発できていました。

今後は VS Code や Emacs といった開発環境でも生産的に開発できるように構成を考慮し、 それぞれの開発者の好みと生産性を両立できるようにしていければと思っています。


トヨクモでは好きなエディタを使って一緒に働いてくれる技術が好きなエンジニアを募集しております。

採用に関する情報を公開しております。 気になった方はこちらからご応募ください。

大学休学 => ゲーム業界でインターン => トヨクモに就職しました

初めまして、開発本部の松尾です。

22年度新卒として、4月にトヨクモに入社しました。

今回は、ゲームプログラマを志して情報系の大学に進学してから、大学を休学し、何故この業界に就職するに至ったのか、経緯を振り返りつつ、新入社員としての初心を書き残して置きたいと思います。

私の進路は比較的右往左往している方だと思いますので、こういう選択もあるのか、などと面白がって読んでいただければ幸いです。

高校生時代

高校生の頃からプログラミングをやっていて、朧げながら、自分はこの業界に進むのだろう、という意識がありました。

プログラミングを始めたきっかけはマインクラフトを始めとするゲームの改造であった為、転じてコンピューターによるエンターテインメント全般に興味が湧き、大学ではメディアプログラミングなどをやりたいと思い、一浪の末情報系の大学に進学しました。

浪人生時代

先程は一行で流しましたが、これまでの経緯を語る上で浪人生時代は欠かせません。 親に顔向け出来たものではありませんが、結論から言うと、この一年私はとにかく自分の好きなものを作るためにプログラミングをしていました。 (ゲームエンジンでゲームを作成したり、当時流行りだしたVTuberを作ってみたり)

是非は今のところ判断しかねますが、この一年が私の今後の人生を大きく変えたと思います。

この一年で2つのことを覚えました

  1. 手を動かすと身につく
  2. 人から教わらなくても、意外と大抵なんでも出来る(当時の主観)

大学生時代 〜前編〜

浪人生時代のある種の放蕩生活は自然な結果に帰結し、第一志望に落ちましたが幸い後期試験で他の国立大学の情報系に進学することが叶いました。

当初は大学生活を謳歌する気に満ちていたので、面白い人や活動に触れられたら良いなと思い、関心がある技術系を中心に数多くのサークルに所属しました。 実際、今でも関わりがあるくらいには、友人関係に恵まれ、これ以上無いという程に大学生活は楽しいものでした。

しかし、一年の後期には、自分の中で大学の単位を取るというモチベーションがほぼ無くなっていたのです。

恐らく謳歌しすぎてしまったのでしょう。下手に技術力の蓄えが(年齢にしては)あったし、当時は音楽など様々な創作にも手を出しており、「割と何でも出来る人」として扱われているうちに、自分でもそう錯覚するようになっていました。

実際、当時の関心の中心は、学術的な知識が必要にならないという意味で、応用的な分野が多かった為か、作りたいものの作り方が思いつかない、という場面に遭遇することはありませんでした。

そして、その分野に於いては、授業や参考書で体系的に知識を得ようとするよりも、実際にハンズオンで学習することが、少なくとも自分にとっては最も効率の良い学習方法である、ということを肌で感じていました。

そうしているうちに、「今自分がやりたいこと」を実現するためには、大学の学位を取るということが、果たしてどれ程重要なことなのだろう、と考えるようになっていました。

大学生時代 〜後編〜

応用的な技術に触れているうちに、自分が手を出したくても出せない領域があることに気づきました。 例えば、当時作っていたモーションキャプチャシステムを小型化したいと考えたときに、今まではノートパソコンを背負ったりしていたものをマイコンに移行したいと考えました。しかし、今までのようにスムーズに行きません。

そこにはOSやドライバという概念があり、今まで目を向けていなかった世界が露出していました。

今まで自分が使っていたツールは、Unityという「ゲームエンジン」で、C#という言語が、Monoという「実行環境」で動いており、デバイスの情報を取得出来るのは、SDKの提供者が、より低レイヤーにアクセスするための「バインディング」を提供しているに過ぎない、ということを悟ったのです。

とにかくこの時点で、自分が使っているツールに対する理解の重要性を思い知りました。そして、いつの間にか私の関心は、なぜコンピューターが動いているのか、3Dモデルを表示出来るのはなぜか?などの、「仕組み」に寄っていったのでした。

そのうち、今まで作品を実現するための手段であった技術が、純粋に関心の対象となりました。(愛を込めて「技術バカ」と呼称しています。)

インターン時代

すっかり技術バカになった私が、改心して大学で真面目にコンピューターサイエンスを学ぶかと思いきや時既に遅し。

尖った人間で有りたい、という自己実現の願望があったのでしょう。

大学の勉強のモチベーションを持ち直すのも難しかったのもあり、

「ここまで来たからには、持ち前の意欲を生かして、社会で通用するレベルの技術を知ろう」

と考え、振り切れることを選びました。大学を休学し、一年間フルタイムでインターンをすることにしたのです。

働かせて頂いたのは、「Cysharp」というCygamesの子会社で、多いと数千単位でスターがついている、有名なOSSを数多く公開している会社でした。

主に開発に携わっていたのは自社製品ですが、ライブラリ製作者の視点で、ときに専門的な知識を活用したりすることもありました。なにより、それを実際に世界レベルで実践している人が近くにいることは、とても新鮮で刺激的な体験でした。

また、新規のOSSライブラリの開発に関わらせて頂いたことも貴重な体験であり、誇らしくもありました。

そして、思わぬ気づきもありました。

  • 技術に長けた人であっても、会社での判断に於いては、「技術バカ」に一歩引いた態度を取っている。
  • コミュニケーション能力は重要

私が「優秀な技術者」として捉えていた方は、CTOでもありましたが、CEOでもあり、確かに商業を成り立たせる為の視点を持っていました。

ここで自分の原点を顧みると、自分にとっての技術は作品を実現するための手段であったことを思い出しました。 それと同時に、「人生において、様々なフェーズで、自分の価値観や関心が変わることがあり、それは自分が思っているよりも高頻度に起こる」ということを実感しました。

それまでもよく話に聞いていたことではありますが、やはり実感が伴って初めて価値観に影響するものです。それまでは、その時々の価値観に従った生き方をしていましたが、近い未来に価値観が変わったり、視野が広がったりすることを前提に行動をしても良いかもしれない、と思うようになりました。

現在

現在、私は岐路に立っています。

会社に入社して、様々なバックグラウンドを持った方々がおり、中には全く別の、高卒=>社会人=>大学というルートを辿っている方もいます。 立派な学歴を持った方の正確な知識に圧倒されることもあるかもしれません。

自分に足りない能力がある。それは大学で得るはずのものだ。と感じたら、夜間に通ったり、大学に戻るということもあり得るでしょう。

価値観が変わっても無駄にならないことはあると思っています。それは成長することであり、今私がこの会社にいる理由の1つでもあります。

トヨクモは、開発のスピード感もあり、優秀な方々がいるので、成長の場としてもうってつけだと思います。 この初心を忘れず、今後の社会人生活も精進していく所存です。


トヨクモでは一緒に働いてくれる技術が好きなエンジニアを募集しております。

採用に関する情報を公開しております。 気になった方はこちらからご応募ください。

医学部を卒業後、トヨクモに就職して1年が経ちました

初めまして、開発本部の細木です。

21年度新卒でトヨクモに入社し1年が経ちました。

今回は就職から1年経って今までの経験などを振り返ってみたいと思います。

就職までの経緯

医師以外の道

高校の進路選択では、将来医師として地元で働きたいと思い、地方国公立大学の医学部に進学しました。 1浪の末合格し進学することはできましたが、その後大学時代を悶々と過ごすこととなりました。

医学の勉強が性に合わず、成績は低空飛行でした。 幸い良い友人に恵まれて何とか進級・卒業することができました。

人の役に立ちたいというモチベーションはありましたし、実習で患者さん達と話すのは楽しかったのですが、生涯これを生業としていくのは肌に合わないなという気持ちがありました。 また医師として働いている方々を見ていて、自分も彼ら・彼女らのようにやりがいを持って働いていけるのか?という不安が拭いきれず、5年生の頃から他の進路について模索し始めました。

ITエンジニアという職業

元々ITエンジニアの職業に対する漠然としたあこがれがありました。 その一方で、医学部を出てから企業へ就職すること自体一般的ではなく現実的ではないだろうなと考えていました。

実習をしていたある日、Lillianさんの転職エントリを目にしました。 この方は東大医学部を卒業し医師として働かれていましたが、心機一転してGoogleに入社されたそうです。 私はこの記事を読んで感銘を受けると共に、医学部卒でもITエンジニアとして雇ってもらうことは不可能ではないのかもしれないと思いました。 その時から就職について本格的に考え始めました。

内定を得るまで

基礎知識をつけるべく勉強を始めました。 Lillianさんのエントリの他、ネット上の記事を漁ってWeb開発の学習に良さそうだと感じたサービスを探し、取り組んでいきました。

Progate(5年生の10月頃〜)

まずは基礎の文法に慣れるためにProgateから始めました。 約1か月でPythonコース、JavaScriptコース、HTML/CSSコースを一通り完了しました。

何もわからない状態から始めましたが、手習いの意味でとても有用でした。 また、フロントエンドの知識は後々の学習の導入として役に立ちました。

AtCoder(5年生の11月頃〜)

基礎的なコードを書く能力がないとコーディング試験に通らないだろうなと考え、Progateの次に取り組みました。

約半年かけて茶色、約1年かけて緑色になれました。

後々のコーディング試験対策として役に立ったのはもちろん、SNS上で多くの人と交流でき、就職に関する情報やチャンスを得ることもできました。

また、はじめはPythonで問題を解いていましたが、マイナーな言語もやってみたくなり途中からはCommon Lispで解くようになりました。これがとても面白く、Lispを書くことに夢中になりました。 この頃からLispで仕事ができたら面白そうだな…と考えはじめました。

Web開発

成果物を作りたいと思い、Udemyで買った講座やネット上のチュートリアル等を進めました。 完成には至りませんでしたが、開発の雰囲気をつかむことができました。

就職活動

自社製品開発をしているスタートアップを中心に、馴染めそうな雰囲気の企業を応募先として考えていました。

応募先を探す中で、ClojureというLisp系の言語を開発に使っている企業があることを知り、それらの企業について調べていると、齊藤さんの退職エントリが目に止まりました。 このエントリを読んで、自分のような変わったバックグラウンドを持った人間でも受け入れてもらえそうだと感じ、応募してみることにしました。

国家試験が終わった翌日、弊社および候補として考えていた複数の企業に応募しました。 いくつか面接やコーディング試験を受けました。

最終的に弊社から内定をもらうことができました。 時期的に新卒は厳しいだろうな…と思っていたこともあり、非常に嬉しかったです。

入社後にやったこと

4〜5月

スケジューラーチームに配属

3日間の入社研修が終わり、早速スケジューラー開発チームに配属されました。

スケジューラーでは主にバックエンドをClojure、フロントエンドをClojureScriptで開発を行っています。 (モバイルアプリはTypeScript)

まずはスケジューラーのコードベースに慣れるため、フロントの易しめなタスクから始めることになりました。 ClojureScriptに加えて、Reagent (Reactラッパー) 、re-frame (Fluxアーキテクチャに基づく状態管理フレームワーク) などが利用されていて、慣れるまでに時間を要しました。 (1〜2ヶ月)

この時期はチームのスピード感に付いていくために必死だった記憶があります。 調べてもわからないことはチームメンバーにたくさん質問しました。

またCursive(IntelliJ)やGitなどの開発ツールを使い慣れていなかったためこれらについても勉強しました。

6〜9月

React Query導入

元々フロントの状態管理はre-frame中心でしたが、React HooksおよびReact Query中心に移行することになりました。 これらについて勉強しつつ、スケジューラに導入するタスクを行っていました。

バックエンド入門

フロントに慣れてきたので少しずつバックエンドを触り始めました。 次のようなことにチャレンジしました。

  • スケジューラーのAPIを構成するライブラリ (Ringstch.sqlなど) について一つずつドキュメントを読み、実際のコードベースに触れつつ学習する
  • SQLの入門書を読む (「SQL 第2版 ゼロからはじめるデータベース操作」)
  • 「テスト駆動開発」を読み、TDDを普段の開発に取り入れる
仕事の仕方について

タスクの進め方を考えたりハマった際の原因探索をしたりする工程に時間を掛けすぎてしまうことがありました。 進めたい内容についてメンターとの間で認識のずれがあると大きな手戻りが起きうるため、手を動かす前にきちんと認識合わせをするようにしました。

10〜11月のファーストリリースまで

この頃は11月のファーストリリースに向けて、残っている未実装機能やバグの対応を行っていました。 体感では一番忙しい時期でした。 (忙しすぎてあまり覚えていない)

11月ファーストリリース後〜3月

ファーストリリース後のバグ修正、機能追加を行っていました。 開発に慣れてきたこともあり、大きめのタスクを担当する機会が増えてきました。

Zoom連携機能

スケジューラーにはZoom連携機能があります。 予定を作成する際にボタン一つでミーティングルームを作成することができます。

予定追加画面からZoomミーティングを作成できる

この機能の公開に向けた修正、申請などを進めていました。 OAuthの理解に時間が掛かりました。 OAuthに詳しいメンバーに教えてもらったりドキュメントと格闘したりしていました。

予定詳細ポップアップの全画面表示

スケジューラーではカレンダー上で予定のカセットを開くとその予定の詳細な情報がポップアップで表示されます。 この表示を画面全体に広げられるようにしました。

予定詳細ポップアップを全画面化

機能要件をまとめ、叩き台実装を作るところから始めました。 開発のメンバーやデザインチームの方々と相談しつつ、UXや細かいレイアウト等を詰めていきました。

最近

大きめの機能実装やDBマイグレーションを伴うリスクの高いタスクが増えてきました。

応用情報技術者試験

CS関連の基礎知識を埋めたくなったので個人的に受験しました。

1年働いてみた感想

自己肯定感を得ることができた

これが就職して一番良かったと感じることです。

弊社で仕事を始めて、至らない部分がありながらも成果や態度が評価され、人間としての自己肯定感を得ることができました。 弊社では、レベルアップしていくために今自分がすべきことが具体的で、やったことの成果が評価としてすぐに返ってきます。 学生の頃と比較してかなり気が楽だと感じます。 (もちろん個人差があると思います)

仕事のスタイルが自分に合っている

普段の仕事では自分の席で黙々と作業する時間が大半です。作業中に割り込みが入ることも少ないです。

私はマルチタスクが苦手で、仕事を自分のペース・段取りで落ち着いて進めることができる今の環境は理想的だと感じています。

Clojureが楽しい

Clojureの良いと感じるところはたくさんありますが、特に以下の点が気に入っています。

  • 書き方で迷う要素が他言語と比較して少なく本質のロジックに集中できる
  • 構文がないに等しく、覚えていないといけないことが少ない
  • 原則immutableで脳に優しい
  • フロントとバックエンドで共通の言語を利用できるため、コンテキストスイッチが小さい
  • 先述の通り疎結合なライブラリが多いため、学習コストが小さく抑えられる
  • 明示的であることが好まれるため、ライブラリの暗黙的な挙動に振り回されることが少ない
  • Structural Editingが便利

非情報系出身でもやっていける

キャッチアップは大変でしたが、なんとか慣れることができました。

勉強すること、必要に応じてコミュニケーションを取ることができる人であれば問題ないと思います。

周りが優秀

新卒、中途を問わず優秀な人ばかりで、周りから日々多くのことを学ばせてもらっています。 特に情報系出身の人・開発経験の長い人などは、自身と比較してかなり地力の差があると感じます。

いずれ追いつけるように努力していきたいですね…

競プロにかなり助けられている

上記の通り、就職活動のため・および趣味で競技プログラミングの問題を解いていました。

開発経験に乏しい非情報系の私が、短い時間で最低限のコーディング力を身に付けて就職できたのは競プロのおかげだったと思っています。

業務で直接的にアルゴリズムの知識を使うことは多くありませんが、言語を使いこなすための基礎的な感覚を身に付ける上で非常に有用だったと感じます。

普通に新卒就活をするならまずWebの勉強をちゃんとするべきだと思いますが、競プロも無駄にはならないと思います。

まとめ

私は医師の道から一転してITの世界に入りましたが、現在もトヨクモで元気に日々を過ごしています。

就職して1年経った今でも、職を得て生活できていること自体奇跡なのでは?と思うことがあります。

今までの縁に感謝しつつ、今後も成長していければと思っています。


トヨクモでは一緒に働いてくれる技術が好きなエンジニアを募集しております。

採用に関する情報を公開しております。 気になった方はこちらからご応募ください。

OSSへの寄付活動について

開発本部の飯塚です。

弊社ではオープンソースソフトウェア(以下、OSS)に対して継続的な寄付という形で開発の支援を行っています。

この件について今まで特にアウトプットがなかったので、これを機にトヨクモがOSSをどう思っているのか、なぜ寄付をしているのかをアウトプットしてみたいと思います。

トヨクモの思い

OSSへの思い

弊社では製品を開発する中で様々なOSSを利用しています。 その中には企業で作られたものもあれば個人で作られたものも当然あります。

それらOSSは弊社製品を形作る重要なピースです。

欠けてしまうと代替の有無に関わらず製品の品質を保つための改修が必須となってしまいます。 つまり利用しているOSSが継続して開発され安心して利用できる状態に保たれていることは、弊社製品開発において品質の担保だけでなく開発効率の向上にも繋がっていると考えています。

寄付への思い

企業はともかく個人で開発されているOSSは、開発にかけられる時間やモチベーションの問題もあり常に継続して開発できるとは限りません。 個人の趣味や興味で作ったOSSは基本的にはお金にはならず、限られた時間の中で無償で開発し続けられる人はごく一部です。 ましてや有名になればなるほどバグ報告への対応などで疲弊する要素ばかり増え、開発をやめてしまうケースも多々あるかと思います。

前述の通りOSSは弊社製品を形作る重要なピースです。 OSS開発者へ貢献に対する感謝を示し、また開発に対するモチベーションの維持などに役立ててもらえたらと願い、弊社では金銭的な寄付を継続して行っています。

寄付状況

現時点(2021/08/27)では Clojure のOSSを主として以下に対して毎月の寄付を行っています。

Thomas Heller氏

Thomas Heller氏は shadow-cljs の開発者です。 github.com

shadow-cljs provides everything you need to compile your ClojureScript code with a focus on simplicity and ease of use.

shadow-cljs は ClojureScript のコードを JavaScript にコンパイルするためのビルドツールで、npm モジュールをシームレスに利用できたり、開発時に必要なREPLの提供などを特徴としています。

Clojure で開発している弊社製品のフロントエンドにおいてはもれなく shadow-cljs を利用しています。 一時期は figwheel-main を使っている製品もありましたが、npm モジュールの利用し易さや開発時の体験の良さから shadow-cljs に移行しています。

今では効率的なフロントエンド開発に無くてはならない存在であるため、継続的な開発を支援するために毎月の寄付を行っています。

Clojurists Together

Clojurists Together とは Clojure コミュニティにおいて定期的に選出されたOSSプロジェクトに対して資金援助し開発のサポートをしている団体です。

援助するための資金は企業や個人からなる有志の寄付から集められており、そこに対して毎月の寄付を行っています。

www.clojuriststogether.org

そのため特定個人への寄付とは異なり、Clojure コミュニティにおける OSS 開発全体を支援している形になります。

前述の通り弊社では Clojure を開発言語とした製品がいくつかあり、 Clojure コミュニティの発展は製品開発の効率や製品の品質に直結します。 よって Clojurists Together への寄付は大変意義深いものと考えています。

今後の予定

今時点での寄付状況は以上ですが、まだまだ足りていないと感じています。

実際に弊社製品で利用しているOSSだけでなく、弊社として今後有望と思われるOSSも対象として寄付による支援を行っていきたいという考えもあり、 今は対象としたいOSSを検討している段階です。

繰り返しにはなりますが、OSSの継続的な開発は弊社における製品開発としても重要な要素の1つであるので、 そこに対して弊社としても利用者の立場として継続的な支援をこれからも行いたいと思っています。


トヨクモでは一緒に働いてくれるエンジニアを募集しております。

採用に関する情報を公開しております。 気になった方はこちらからご応募ください。

トヨクモ株式会社を退職します

開発本部の齊藤です。2021年の1月で退職することになりました。業務内容の紹介も兼ねて今まで何をやってきたか、これから何をするかについて書きます。

入社までの経緯

私はもともと大学の学部を卒業した後に大学院の修士課程に進学する予定でしたが、卒論があまりうまく行きませんでした。なんとか先生に介護してもらいながら卒論を終えたものの、自分で思うような卒論が書けず、 「大学院に進学しても地獄のような思いをするだけでは?」という思いが強くなっていきました。今から振り返ると、結局はあまり興味がない分野(バイオインフォ)を選んでしまったことが卒論の失敗の根本的な原因だったと思います。

大学院進学をあきらめた私は、とりあえず生活のためにどこかに就職しようと思いました。とはいっても何をすればいいかわかりませんでしたし、すでに2月になっていました。 ひとまず、すでに会社員をやっている知り合いに連絡を取って助言をもらえないかと考えました。 そこで、以前SICP勉強会で面識のあった北川さんに連絡をとることにしました。すると、「バイトから社員のコースに載せられるかも知れないので、とりあえずバイトをしましょう」という話になり、2月からアルバイトをすることになりました。

アルバイトでは、Vue.jsやClojureの勉強をしてのんびり過ごしていました。製品には1行だけコミットした記憶があります。FormBridge のボタンが消えるみたいなバグの修正だったと思います。 「4月から9月まで契約社員で採用します」という話だったので、是非お願いしますと言って入社しました。契約社員とはいえ、福利厚生などの待遇面では賞与以外の違いはなかったと記憶しています。家賃補助や、タイミングが良かったためストックオプションも貰えました。

入社してからやったこと

kintone-query-builder (2019年4月)

kintone-query-builder-phpというクエリビルダを作って社内製品でも利用するようにしました。PHPを書くのは初めてだったのですが、PHPStormが助けてくれたので、ひとまず完成できました。 詳細についてはブログ記事にも書きました。

kintone REST API向けのPHPのクエリビルダを作りました - Toyokumo Tech Blog

pc-auto-save (2019年5月)

pc-auto-save.jsというプリントクリエイターの機能を拡張してくれるJavaScriptのメンテナンスを行いました(現在はプリントクリエイターの標準機能として取り込まれたため、このJSは存在していません)。 このJavaScriptはClojureScript製で、私が「Clojureやりてぇ〜」と訴えたらこの仕事にアサインしてくれました。ちょっとした不具合の修正が目標だったのですが、結局Reagent(Reactのラッパー)で 書き直しました。Clojureの良い練習になりましたし、REPL駆動開発やStructural Editingに慣れることができました。SICP勉強会でだいぶSchemeには慣れていたのですが、原始的な開発環境で開発していたため、 Clojureの素晴らしい開発環境、ツールに感動しました。

この時期にOn Lisp勉強会を開き始めたのもいい思い出です。結局コロナなどもあって、現在は凍結しているのですが...。 私はあんまり人に話しかけるのが得意ではないので、勉強会を通して他の社員と交流できたのが良かったなと思いました。

kMailer (2019年6月~10月)

6月からはClojure製品の1つであるkMailerの仕事をしました。ブラウザのdevtoolなどを使ってボトルネックを見つけて修正したり、大量のデータでの挙動を改善するような仕事を経験できたので勉強になりました。一定以上のデータを使うときにconcatで爆発するというのがあり、遅延評価は難しいなと思いました。 データマイグレーションなどの慎重さを求められる仕事もあったのですが、開発本部の先輩が仕事の進め方や技術的な知識をアドバイスしてくれたおかげでなんとかうまく行きました。 また、インフラをElastic Beanstalkに移行するという仕事も経験することができました。EBは便利ですね。

9月には正社員に登用されることになり、給料も上がって嬉しかったです。

新製品DataCollect (2019年11月~2020年5月)

11月からは新製品DataCollect開発にアサインされました。DataCollectでは、エクセルのような式を書いて、kintoneのデータを利用して計算をすることができるのですが、その「エクセルライクな式を処理して計算をする」モジュールを僕が作成することになりました。 ちょっとした外部DSL的なものです。

;; 目標は以下のような関数compileを作ること
(compile エクセルライクな式の文字列)
;; => 以下のようなmapが返ってくる
{
 :compiled-fn (fn [input] ...) ;; inputを与えると実際の計算をする
 :how-to-build-input ... ;; compiled-fnに与えるinputを作り上げるために必要な情報
 }

かねてから「(プログラミング)言語処理系とか興味あるんですよね〜」と言っていたので、興味や適正を加味してのアサインでした。 開発は私と開発本部長の木下さんの2人でしたが、私にとっては少人数でも初めてのチーム開発でした。 仕様を無から作り上げていくという初めての体験ができましたし、チーム開発を通して技術的なコミュニケーションのスキルが上がったと思っています。疑似コードで議論するのは楽しかったです。 3月にリリースしてからは、ユーザの利用できる関数を追加したり、配列 + 1のような計算間違いをコンパイル時に検出してユーザに提示する、簡易型チェックの仕組みを作ったりしました。

技術的には「たぶん作れるだろうな〜」と思っていたのですが、実際に製品に組み込むとなるとやはり不安になるものです。一通り必要な要件を満たすものを作成できて自信になりました。

リリース後は私がDataCollectを一通り見る役目として、バグ修正や機能追加、コードレビューをやりました。 トヨクモ株式会社は製品がとても多いため、1人1製品くらいの状況になるので、責任感と緊張感を味わえたのは良い経験だったと思います。

別の新製品開発 (2020年6月~)

2020年の6月からは仕事の中心が新製品開発が中心になりました。「最速で製品をリリースする」のが当初の目標だったため、 ひとまずDataCollectのリポジトリをクローンしてその上に新規機能を実装しキメラのようなアプリを作り、その上で不要な機能を削除するという開発方針で進めていました。 開発本部の方針として「製品の差別化につながらない部分にコストを割かないようにする」というのがあるためです。

DataCollectの開発では、Webインターフェースやバッチ処理の部分はほとんど木下さんが作ったため、ClojureのWeb開発はほとんどやってませんでした。 新製品開発はしばらく私一人での開発だったため、全部やる必要があり、ClojureのWebアプリケーション開発にだいぶ慣れることができたと思います。

また、新製品開発のコツなどもアドバイスしてもらい、勉強になりました。

  • やることの全体像を(スプレッドシートなどで)可視化する
    • モチベーションの維持に役立つ
    • やることを明確にできる
    • 他人に何をどこまでやっているのか共有できる
  • UIのモックから作る
  • 非機能要件は、機能要件を固定してからテストを書いた上で取り組む

結局、リリースすることができませんでしたが、現在も開発中です。

会社員生活の感想

  • 知り合い(北川さん)が社内にいたため、割とすぐ馴染めたと思います。知り合い経由で就職するとその点楽だなと思いました。
  • 私は自分の意見が通らないと面白くないなと思ってしまう人間なので、妥当性があれば誰の意見でも採用してくれる雰囲気は私にあっているなと思いました。また、人数が少ないため、その分一人ひとりの裁量が大きくなっているのもフィットしていたかなと思いました。自分の貢献が明確なのでやっていて楽しかったです。
  • 新製品開発ばっかりやっていたような気がします。会社の方針として、「1つの製品に機能を大量に盛るのではなく、シンプルな製品を多くリリースする」というのがあり、新製品開発に関わりたい人には良い環境だと思います。
  • 規模の大きい製品で、パフォーマンスなどが問題になる部分を担当する機会がなかったのはもったいなかったかなと思いました。安否確認サービスという製品があるので、体験できるチャンスはあったと思うのですが、私は一切関わりませんでした。
  • Clojure(LISP)で仕事をできる環境は日本ではとても限られているので、「Clojureで仕事する」というレアな体験ができてよかったです。実際ほとんどClojureしか書いてませんでした。
  • 給料がドンドン上がっていくのが面白かったです。正社員になったタイミング、2019年12月、2020年6月、2020年12月のタイミングで上昇し、最終的には契約社員時代と比べて約月給が1.5倍になりました。なぜ月給ベースでの上昇割合を書いたのかと言うと、2年未満しか勤めていないため実年収のサンプルが1つしかないですし、昇給のタイミングが1年に複数あったため誤解が生まれない書き方がわからなかったためです。トヨクモ社の2020年度まで年収モデルとして、月給x14がベースの年収として考えられるため、実際の年収に換算しても1.5倍であってると考えられます。
  • 会社の上場を経験できました。といっても、未だに上場の意味などもよく分かっておらず、会社に胡蝶蘭が来て「へぇ〜」と思ったくらいの感想しかありません。私のストックオプションも行使権を得る前の退社により破棄されるので関係ないですし...。
  • 大学でいろいろあり、入社時にはノイローゼのような状態になってしまっていましたが、一定の収入があり、人間らしい生活ができると自然と回復していくものなんだなと思いました。特に2020年になってからはだいぶ元気を取り戻した感じがありました。貯金残高を眺めて精神状態を回復させるのはよく使っていました。
  • slackのemojiを追加して遊ぶのは楽しかったです。自分が追加したemojiを他の社員が使ってくれると嬉しくて積極的に追加していました(一部「治安が悪い」という理由で撤去されたものもあります)。
  • 朝起きて夜寝る生活ができるようになりました。

なぜ退職するのか

退社後は大学院修士課程に進学して項書換え系 の研究をする予定です。定理証明支援系やプログラミング言語の基礎に興味があるので、研究は楽しめるのではないかと考えています。

もともと研究職に対する漠然とした憧れがあり、いつかは挑戦してみたいなとはおもっていたのですが、暇な時間を使って勉強しているうちに早く挑戦してみたい気持ちが強くなったので、このタイミングで挑戦することにしました。

木下さんとの退社の面談でも「ストックオプションの行使権の取得まで待って挑戦する選択肢もあるのでは?」というアドバイスも受けたのですが、新しいことをやるには勢いが大事だと思っているので、熱意が冷めないうちに退職したほうが良いだろうなと判断しました。やりたいことを我慢しながら別のことをするのは精神的に耐えきれない人間なので、爆発する前に決断できて良かったと自分では思っています。

また、会社員をやりながら大学院に進学したりする選択肢もあるとは思うのですが、私の最終的な目標としては研究者としての職を得ることなので、大量に時間を確保する必要があると思ったので候補から外れました。

退職を心に決めたのは2020年の5月でしたが、それ以来モチベーションを維持するのが難しくなってしまい、とてもしんどかったです。加えて 、退職が近づくにつれドンドンやる気がなくなっていきました。100%のパフォーマンスが出せていない状態が長く続いてしまい、申し訳無さを感じています。

研究をやるにしろ、会社員的なスキルは大事だと思われるので、会社員をやったことは悪くなかったかなと思います。また、ソフトウェア開発のスキルはしばらく需要が高いと考えられるので、挫折してもまた再就職すればいいやーというセーフティネットがあると思うと、学部時代のような漠然とした不安感に苛まれることもなく、前向きに生活できるのではないかと期待しています。博士号取れるようにとりあえず5年間は頑張りたいと思います。実はまだ入試に受かってすらないのですが...。

ありがたいことに「暇になったらアルバイトしてくれ」と言われているので、また仕事するかもしれないです。


トヨクモでは一緒に働いてくれる技術が好きなエンジニアを募集しております。

採用に関する情報(https://scrapbox.io/toyokumo-recruit/)を公開しております。 気になった方はこちらから(https://toyokumo.co.jp/jobs/)ご応募ください。

メール送信ライブラリ tarayo のすすめ

開発本部の飯塚です。

今回は担当している製品で利用しているメール送信ライブラリを自社製のものに移行した経緯や利点などをまとめてみました。

概要

  • kMailer というサービスの開発/運用を行っている
  • コア機能であるメール送信のライブラリとして postal を使っていたが問題点がいくつかあった
  • その問題点を解決しているライブラリが他になかったので開発し、移行した

kMailer とは?

kMailer ロゴ

kMailerkintone 内に登録されているデータを利用してメール送信するというサービスです。

コア機能であるメール送信をする方法としては現状、以下2つの方法を提供しています。

  • お客様のSMTPサーバーを利用したメール送信
  • Google との OAuth 連携を利用したメール送信

今回は前者の「お客様のSMTPサーバーを利用したメール送信」で利用しているライブラリの移行の話です。

postal とは?

postal は Clojure でSMTPによるメール送信をしようとした場合の デファクトスタンダードと言っても過言ではないライブラリです。 SMTP の他に sendmail を使ったメール送信にも対応しています。

以下、テスト用メールサーバーを使ってメール送信をする簡単な例です。

(require '[postal.core :as postal])

(postal/send-message {:host "localhost" :port 1025}
                     {:from "alice@example.com"
                      :to "bob@example.com"
                      :subject "hello"
                      :body "postal world"})

postal の問題点

postal の API はとてもシンプルで postal.core/send-message が提供されているのみです。 この関数に接続先のサーバー情報とメールの内容を渡せばそれだけでメール送信をしてくれます。 とても簡単で良いのですがいくつか問題がありました。

  1. 開発が止まっている JavaMail に依存している
    • JavaMail は ver 1.6.2 のリリースを最後に Eclipse Enterprise for Java の一部となり Jakarta Mail と名前が変わり、こちらで開発が続けられています。
    • JavaMail には宛先として不正なメールアドレス(例えば bob@example.com. のように末尾がドットで終わる)を渡しただけでも NullPointerException を投げる問題があり、後継の Jakarta Mail を使いたいという要望がありました。
      • Jakarta Mail の場合 javax.mail.internet.AddressException 例外が Domain ends with dot というメッセージと共に投げられるのでとても親切です。
  2. 一度に複数のメールを送った場合のエラー時の挙動
    • 複数のメールを送信する場合、単純に doseq でループを回しているだけなので、途中で前述のような NullPointerException が投げられてしまうとそれ以降のメール送信は止まってしまいます。
      • その上、リクエスト処理の結果は doseq 内で捨てられてしまっているため、どこまで送信リクエストが完了したのかもわかりません。
  3. メールサーバーとの接続/切断が暗黙的
    • 複数のメールを一度に送信する場合でメール単位の結果を取得しようとすると、メール単位で postal.core/send-message を呼び出すしかないのですが、メールサーバーとの接続/切断は関数内で閉じられてしまっています
      • そのため、例えば Gmail (smtp.gmail.com) を使ったメールの一斉送信をしようとすると、メールサーバーへの接続/切断を繰り返しすぎて Too many login attempts エラーが簡単に発生してしまいます。

後者2つの問題解決のためのプルリクエストは出したもののマージには至らなかったので、kMailer では postal をフォークして改修したバージョンを製品に使うという中途半端な状態が続いていました。

tarayo とは?

tarayo は postal での問題点を解決するために弊社が開発した SMTP クライアントライブラリです。 名前の由来は郵便局の木として知られるタラヨウからです。

postal との主な違いは以下の通りです。

  • Jakarta Mail ベース
  • SMTP のみをサポート (単一機能のみを提供)
  • メールサーバーとのコネクションが明示的

以下、postal でのメール送信例を tarayo を使って書き換えたものです。

tarayo ではメールサーバーへの接続(tarayo.core/connect)とメール送信(tarayo.core/send!)を別々の関数として提供しているので、 postal ほど簡単ではありません。(with-open しているだけなので十分簡単ではありますが)

(require '[tarayo.core :as tarayo])

(with-open [conn (tarayo/connect {:host "localhost" :port 1025})]
  (tarayo/send! conn {:from "alice@example.com"
                      :to "bob@example.com"
                      :subject "hello"
                      :body "tarayo world"}))

tarayo でどう postal の問題点を解決しているか

では postal にあった問題点を tarayo ではどうやって解決しているかを簡単にまとめてみました。

  1. 開発が止まっている JavaMail に依存している
    • tarayo は最初から Jakarta Mail ベースで開発しています。
  2. 一度に複数のメールを送った場合のエラー時の挙動
    • tarayo.core/send! は1通のメール送信だけを扱う関数としています。
      • そのため複数のメールを一度に送る場合はライブラリの利用者側でループする必要はあります。
      • 1通の送信だけが対象なので、結果は勿論捨てずに返しており、送信対象と結果の紐付けも容易です。
  3. メールサーバーとの接続/切断が暗黙的
    • メールサーバーへの接続をするだけの関数として tarayo.core/connect を提供しています。
      • これにより with-open マクロなどを使って明示的に接続を切る必要は出てきますが、切断するタイミングを任意に決められるので一斉送信などをする場合により柔軟な対応が可能になっています。

kMailer で利用する上での問題点の解決を第一に開発したライブラリではありますが、なかなか使い勝手の良い出来になっているかと思います。

最後に

kMailer ではすでに postal から tarayo への移行が完了しています。 平日1日で数万通のメールを送っていて、これらがすべて tarayo でカバーされるメールです。

接続先のメールサーバーはお客様の設定次第であり多岐にわたるため、postal から tarayo への移行後に接続できなくなるメールサーバーが出ないかの不安はありました。 しかし今のところそういった問題は見つかっておらず健気にメール送信処理を頑張ってくれています!

このようにある程度の規模での利用実績も積めたので、もし Clojure でメール送信をする機会がありましたら一度 tarayo を試してみていただければなと思います。


トヨクモでは一緒に働いてくれるエンジニアを募集しております。

採用に関する情報を公開しております。 気になった方はこちらからご応募ください。