株式会社Casa TECH BLOG

日々、FAX/電話/紙等リアルと戦う事業系IT部門の戦士たちのブログです。

文系出身のプログラミング未経験が入社して1年経ったので振り返ってみた

自己紹介

はじめまして。Casa IT戦略部の小倉と申します。
2021年3月よりエンジニア未経験として中途入社し、早くも1年が経ちました。 今は不動産の代理店向けサービスの開発に携わらせてもらい、機能の追加や修正を担当しています。

これまでの経歴をざっくりまとめますと、文系の大学を卒業し電気施工管理会社に入社。電気工事士として新築マンションやオフィスビルの改修工事、マンションのオートロック化などを経験し、そこから物件の完成後に興味を持ったため、不動産の仲介会社の営業へ転職。 その後プログラミングスクールを卒業しCasaに入社しました。

↓スクールで作成したアプリです。 github.com

なぜエンジニアを目指そうと思ったか

不動産の営業として勤めていた頃、物件の賃貸借契約における重要事項説明は、店舗へ来店していただき対面で宅建士から説明を受ける必要がありましたが、オンライン上で重説を行うIT重説を徐々に導入するようになりました。

それに合わせてオンライン内見なども導入されはじめ、これによって契約締結のために来店していただく必要がなくなり、一つの契約にかかる時間が削減されましたが、当時はまだ賃貸借契約は全て紙で行われていたため、契約書への記入ミスなどがあれば書き直しのために再度書類を郵送し直す必要がありました。そういった作業に対して費やす時間がとても多く、営業活動に費やす時間が削られてしまったりと、無駄に感じることがまだまだ不動産業界には多かったです。

この先不動産業界のIT化が進めば、時間だけではなく契約に必要な紙や郵送費用などが削減できるので、結果として業務効率を上げることもでき、営業活動にかける時間を増やすことができるのでは?と考え始め、IT業界の力に可能性を感じたことがきっかけでした。

研修期間(入社〜3ヶ月)

入社後の研修期間では、タスク管理のアプリを作成しました。
要件定義ではペーパープロトタイピングで画面遷移図の作成や、モデルの設計図などに対してレビューをいただいたうえで実装に入りました。

使用した言語・ミドルウェア

主な実装機能

・ユーザ登録 (ログイン、ログアウト) ・ユーザに管理者権限を与える ・タスク登録機能 ・一覧表示 (ページネーション) ・詳細表示 (編集、削除) ・タスク検索、絞り込み、並び替え機能 ・タスクに終了期限をつける、優先度、状態を登録 ・タスクにラベルをつけて分類

苦労した点

  • スケジュール管理
  • Git、GitHubの操作

頑張った点

  • SQLの操作(コンソールでdbからデータを取得)
  • gemを使用せず実装した機能
    • ログイン・ログアウト
    • タスクのタイトルやステータスでの検索

研修を通して得られた学び

  • プルリクの粒度をなるべく小さく、機能単位で提出すること
  • コードのコピペで終わらせず、なぜこうなるのか?を根本から考えるよう意識して表面上の浅い理解のままにしない
  • 質問される側のことを考えて、思考を整理して質問する
  • 分からないことがあれば読み辛くても最新の公式ドキュメントを読む
    当時は参考にした記事のRubyRailsのバージョンを意識せずに実装したことが原因で、バージョンアップによってデフォルト値が変更されたため記述が不要になったメソッドを書いていたことについてレビューで指摘がありました。(protect_from_forgery メソッドや、form_withメソッドのオプション local: true など)
    技術記事は読みやすいので公式ドキュメントを避けがちでしたが、そういった指摘をいただいてからは最後に確認してから実装に入るようになりました。
  • gemの導入時は、PRにGitHubのリンク等を貼る
    個人アプリの開発では、なぜこのgemを採用するのかを意識せずに参考にしていた本や動画などで紹介されるがまま実装していたため、その感覚で開発していましたが、実際の現場では導入したいgemのGitHubを確認して、star等の数で利用者数や、コミットログ、PRを見てメンテナンスされているのかを見たりして、gemを導入して良いかの判断材料にしたり、同じ用途で複数の有力なgemがある場合には、なぜそのgemを採用したかなどの理由を書き、チームで判断したうえで導入を決めることを学びました。

初めての実装(4ヶ月目〜)

初めてのタスクはSMSの文言を動的に変更させるといった修正でした。
生のコードを見るのはこれが初めてでしたので、先輩エンジニアの方々が書いたコードに手を加えて良いのかとビクビクしながらの実装でしたが、無事にリリースされた時はとても達成感がありました。

実装で経験したこと

入社してから苦労したこと

  • WEBの仕組みについて
    この辺りは本を読んだり、基本情報技術者の勉強を進めていくことで基礎を学びました。

  • SQL
    DBの大量のテーブル同士を必要な条件で結合して情報を取ってくるには、どこに何の情報があるのか、ある程度はテーブルを把握しておく必要がありますし、何よりSQL自体書いたこともないところからのスタートでしたので、大変苦労しました。 ここは入社前に勉強しておくべきだったと反省しています。

  • git
    gitについてはスクールや個人開発でも利用していたのですが、 チーム開発は経験がなかったため、ブランチルールの理解やコンフリクトの解消など、gitの操作など色々と覚えることが多かったです。

今後の目標

  • 学んだことについて記事にする
    月に1冊は新しい技術書を読み、3ヶ月に1度は記事を書くようにします。 技術記事を書くことで、言語化能力をつけ、知識を定着させていこうと思います。

  • 今年の夏に Ruby Gold に合格する

  • 個人アプリを開発する

  • 勉強会を続ける
    週末はスクールの同期と集まって勉強会を実施しています。 自分のモチベーションを上げる良い時間になっているのでこれからも続けていきたいです。

1年を振り返って

始めの頃は手が詰まり実装が思うように進まないことが多く、1人で抱え込んでしまうことが多かったです。

そういった悩みも週に1度の上司との1on1ミーティングや毎日の夕会での進捗共有など、チームに相談や質問がし易い環境がありますので、 詰まってる部分の解決のためのヒントや、今自分に足りない部分や業務を進めていく上でのアドバイスをいただき解消することができています。

また、ペアプログラミングを通して先輩エンジニアのコードの書き方やデバッグの方法、既存コードの見方や処理の流れを学ぶことができました。

質問したいけど何が分からないのか分からない状態だった始めの頃と比べると、ここまでの処理はできているがこの先の処理が上手くいかない。というように切り分けができるようになってきたことで、質問したい箇所が具体的になってきたかなと感じています。

まだまだ先輩方からのサポートをいただきながらではありますが、 チームの1人として開発に入らせていただき、既存サービスへの機能追加では、要件定義から基本設計、開発、テスト仕様書の作成、テスト実施まで一通りの流れを経験させてもらえたり、上流工程を早いタイミングで経験することができている環境に大変感謝しています。
早く1人前のエンジニアになれるように、これからも邁進していきたいと思います。

WordPressで電子マニュアルを作る

はじめまして。開発担当の坂﨑です。主にPHPを用いての開発を担当しています。

不動産管理会社・仲介会社向けのWEBサービスや賃貸人向けのWEBサービスのマニュアルをWordPressで管理できるように開発を行いました。
紙のマニュアルだと
「更新までに日数を要する、特定部署に依頼しないと更新できない」
という問題がありました。
「更新がスムーズに行えること、部署に関係なく更新が可能になること」
を実現するため、一からシステムを構築するよりも、WordPressを使えばスムーズに更新ができ、更新できる人数が増えると考えました。
また、WordPressで1つ作成すると同様の手順で色々と作れるようになるため、その手順を記載したいと思います。

WordPressワードプレス)とはPHPで作られているCMSコンテンツマネジメントシステム)の1つです。
https://ja.wikipedia.org/wiki/WordPress

空のテーマを用意する

インストール後にWordPressを起動するとデフォルトでテーマが選択されています。
マニュアル用のヘッダやフッタを使いたくてもデフォルトのテーマが影響して思い通りの動きにならないことがあります。
そこで空のテーマを用意し、必要なものを後から付け足すようにします。

footer.php
header.php
index.php
style.css

最低限必要なファイルはこれだけですが、投稿された記事用のテンプレートやサイドメニュー用のテンプレートなどを追加し、CSSJavaScriptも配置すると以下のような構成になっていきます。

wp-content
└─theme
    └─空のテーマフォルダ
        ├─css
        │   └─CSSファイル
        ├─images
        │   └─ロゴやヘッダ画像など
        ├─js
        │   └─JavaScriptファイル
        ├─templates
        │   └─記事用のテンプレートファイル
        ├─footer.php(フッタファイル)
        ├─functions.php(共通処理)
        ├─header.php(ヘッダファイル)
        ├─index.php
        └─style.css

大枠はこれで完成です。デザイナーと調整してCSSファイルやJavaScriptファイルの追加や修正を入れて見た目を整えていきますが、空のテーマフォルダをzip形式に圧縮し、WordPressの管理画面からテーマをアップロードします。

WordPressの管理画面で行うこと

WordPressの管理画面にログインし、メニューの「外観」を選択すると画面上に「新規追加」ボタンがあります。
この「新規追加」ボタンを押下してテーマフォルダをアップロードします。
空のテーマが有効になればデフォルトのテーマの影響を受けずに思い通りの動きを実現できるようになります。

アップロードしたフォルダ内の『index.php』はTOP画面のテンプレートとして使われます。
また、記事を投稿する際はテンプレートに記事用のテンプレートファイルを設定して投稿します。
カテゴリを設定することで記事をカテゴリごとに分類することができます。

記事を表示する際に利用する関数

管理画面から記事を投稿して公開したら、次は記事を表示する処理を作っていきます。
まずはサイドメニューなどでカテゴリと記事の一覧を表示するための情報を取得します。

<?php 
$args = array(
    'orderby' => 'id',
    'hide_empty' => '1',
);
$categories = get_categories($args);
?>

記事が紐付いていないカテゴリは含めず、idの順番で取得するように指定します。 続いてカテゴリに紐付く記事を一覧で取得します。

<?php 
foreach ($categories as $category) {
    $list = get_posts(array(
        'post_type'      => 'post',
        'cat'            => $category->cat_ID
    ));
}
?>

一覧で記事のリンクが選択された際の記事ページの表示は以下のようにします。

<h1><?php the_title(); ?></h1>
<?php the_content(); ?>

the_title()で記事のタイトルを表示します。
the_content()は記事の本文を表示するために使います。

注意した方が良い点

ここまでで一覧ページから記事の詳細画面までを作ってきましたが、WordPressの開発時に注意した方が良い点をまとめました。

キャッシュ対策

CSSJavaScriptを修正し、いざ本番に反映したはずなのに、キャッシュが残っているためか変更が反映されていないことがあります。

href="<?php echo get_stylesheet_directory_uri();?>/style.css
    <?php echo '?' . filemtime(get_stylesheet_directory_uri() . '/style.css'); ?>"

読み込むCSSJavaScriptのURLが変われば、キャッシュではなく本体を見にいくようになるため、filemtime()でstyle.cssのタイムスタンプを取得し、CSSJavaScriptを読み込む際にパラメータとして付与する方法です。
CSSJavaScriptを修正した時に、タイムスタンプが変わるためキャッシュではなく修正した本体が使われるようになります。

カスタムフィールドによる記事のソート

カスタムフィールドに共通のキーを設定し、値にソート順を入れることで記事の並び順を任意に設定することができます。
その際にカスタムフィールドを設定した記事と設定していない記事が混在すると全ての記事をうまく取得できないことがあります。

<?php 
// カスタムフィールドを設定した一覧
$list = get_posts(array(
    'post_type'      => 'post',
    'cat'            => $category->cat_ID,
    'posts_per_page' => 20,
    'pages'          => 1,
    'orderby'        => 'meta_value_num',
    'order'          => 'ASC',
    'meta_key'       => 'sort_key'
));
// カスタムフィールドを設定していない一覧
$no_custom_list = get_posts(array(
    'post_type'      => 'post',
    'cat'            => $category->cat_ID,
    'posts_per_page' => 20,
    'pages'          => 1,
    'meta_query'    => array(
        array(
            'key' => 'sort_key',
            'compare' => 'NOT EXISTS'
        )
    )
));
$list = array_merge($list, $no_custom_list);
?>

この場合はカスタムフィールドを設定した一覧と、カスタムフィールドを設定していない一覧を取得し、array_mergeで1つのリストに結合することで実現することができます。

おわりに

開発者目線で見るとデザイナーにHTML、CSSJavaScriptを作成してもらってから、WordPressのテンプレートとして組み込むのは、時間を要しますが難易度はそれほど高くないと思います。
マニュアルとして記事を投稿したらデザインがあたった綺麗なページとして表示されると、他のサービスでも使ってみたいという声が出てきたのは嬉しかったです。

今回は書けませんでしたが時間があったら、 記事を投稿したらS3にHTMLを出力し、そのHTMLのみにアクセスさせることでセキュリティを向上した方法を載せたいと思います。

サービスのバグ発見をきっかけに初めてOSSにコントリビュートした話

はじめまして。エンジニアの辻本です。Casaの代理店である不動産管理会社・仲介会社向けのWEBサービスの開発を担当しています。

普段、Ruby / Ruby on Railsを用いてサービスを開発しているのですが、少し前に、サービス内のかなり稀にしか起きないバグを発見し、そのバグ対応をきっかけに、初めてOSSにコードを書いてPRを出しました。無事マージされたので、その経緯を書いていきたいと思います。

github.com

※ドキュメントを和訳するPRは以前出したことがあり、厳密に言うと初めてのPRではないです。コードを書いてPRを出すのは今回が初めてなので、タイトルは少し盛っているのをご了承ください!

サービス内のバグを発見

バグの原因となっているRubyのコードは下記のようなものでした。

module Foo
  module_function

  def call(params)
    @params = params

    # do_something
  end
end

すぐ気づく人は気づくかもしれませんが、スレッドセーフじゃないですね。module_functionによって、メソッドがモジュール関数となりますが、モジュール関数はモジュールの特異メソッドであるため、Foo.call(params)のように呼び出すことができ、このとき、モジュールのコンテキストで状態をもってしまっています。マルチスレッドな場合、スレッド間でモジュールの状態は共有されるため、一方でインスタンス変数を書き換えるともう一方のスレッドにも影響を与えてしまうということになります。

開発しているサービスではpumaを利用していますが、pumaはマルチスレッドで動作するため、かなり稀に複数リクエストがモジュールを同じタイミングで呼び出してしまいバグが発生していました。

スレッドセーフじゃないコードを書いてしまったことによって意図しない挙動が起きる簡単な例を以下に示します。

module Foo
  module_function

  def call(name, number)
    @number = number
    puts "#{name}\t#{@number}"

    sleep 1
    @number += 1

    puts "#{name}\t#{@number}"
  end
end

t1 = Thread.start { Foo.call("Alice", 1) }
t2 = Thread.start { Foo.call("Bob", 10) }
t1.join
t2.join

Aliceのスレッドでは開始時に1、終了時に2と出力するのを意図していますが、Bobのスレッドがcallの1行目でインスタンス変数を上書きしてしまうため、Aliceのスレッドの終了時には11が出力されてしまっています。

$ ruby main.rb
Alice   1
Bob 10
Alice   11
Bob 12

スレッドセーフじゃないコードを自動で発見できないか?

今回のバグ調査では、目視で対象を洗い出して対応したのですが、こういうのってRuboCopとかで発見できないのかな?と思い調べてみました。すると、rubocop-thread_safetyという、いかにもそれなgemを見つけました。

スレッド間で状態を共有してしまうとして、Class instance variables (@name in class context or class methods) というような説明もあったので、インスタンス変数を不適切に扱っているところを検出してくれそうです。

試しにgemを入れてrubocopを実行してみました。

$ bundle exec rubocop main.rb
Inspecting 1 file
.

1 file inspected, no offenses detected

残念ながら今回のケースは検出できませんでした。クラスメソッド内でのインスタンス変数の利用は検出してくれるようですが、モジュール関数内での利用は検出してくれないようでした。

OSSにPRを出してみた 🎉

残念ながらrubocop-thread_safetyではモジュール関数内でのインスタンス変数を検出してくれないようでしたが、クラスメソッド内でのインスタンス変数の検出などで似たようなことをやっているはずだし、コードベースも小規模で把握しやすそうなので、自分で実装してPRを出してみようと思い立ちました。

RuboCopのCustom Copの書き方を調べながら、頑張って実装して出したPRがこちらです。

github.com

↓のように怒ってくれるようになります。

$ bundle exec rubocop main.rb
Inspecting 1 file
C

Offenses:

main.rb:5:5: C: ThreadSafety/InstanceVariableInClassMethod: Avoid instance variables in class methods.
    @number = number
    ^^^^^^^
main.rb:6:22: C: ThreadSafety/InstanceVariableInClassMethod: Avoid instance variables in class methods.
    puts "#{name}\t#{@number}"
                     ^^^^^^^
main.rb:9:5: C: ThreadSafety/InstanceVariableInClassMethod: Avoid instance variables in class methods.
    @number += 1
    ^^^^^^^
main.rb:11:22: C: ThreadSafety/InstanceVariableInClassMethod: Avoid instance variables in class methods.
    puts "#{name}\t#{@number}"
                     ^^^^^^^

1 file inspected, 4 offenses detected

実装としては、インスタンス変数を利用している箇所に対し、モジュール関数内で呼ばれているかどうかを AST をたどって判定しています。Custom Copを実装するための抽象化された仕組みをRuboCop側が用意してくれているのもあり、既存のコードを見ながら頑張って何とか実装することができました。どちらかというと、PRの説明を書くのに苦労した覚えがあります。

おわりに

今回出したPRはその後無事マージされました!

ただし、マージ後にまだ新しいバージョンがリリースされていないので、リポジトリとブランチを指定する方法で利用する必要があります。よければぜひ使ってみてください。

gem "rubocop-thread_safety", git: "https://github.com/rubocop/rubocop-thread_safety.git", branch: "master"

なお、PRをやりとりしていた時点ではサードパーティのgemだったのですが、その後、リポジトリがフォークされてRuboCop Headquartersに移管されており、公式のgemとなっているようです。rubocop-railsrubocop-rspecと同じ立ち位置ですね。

Docker Desktopの代替品を探してみた

皆様初めまして、株式会社Casaにてインフラやサービス開発を担当している佐々木と申します。

今回の記事は
2021年中頃、Docker Desktopが有料化されたので、代替品を探し触り心地やRancherでのつまづきを紹介したいと思います。

有料化の詳細はこちら:
https://www.docker.com/blog/updating-product-subscriptions/

本日のお品書き:

代替品の候補

1 lima

対応OS : mac
所感:インストールがちょっと煩雑でローカル構築には向かないかなぁ。
公式リンク:
https://github.com/lima-vm/lima

2 Rancher Desktop

対応OS : Mac , Windows , linux
所感:インストーラー付きでGUIも有り、使いやすさはDocker Desktopとほぼ同等かな。
公式リンク:
https://rancher.com/products/rancher

3 DockerのCLIを使い続ける

所感:limaよりかは良いが、やっぱりGUI欲しいなぁとなっちゃう。

Rancher Desktopインストール手順

1 公式からインストーラーをDL。

rancherdesktop.io

2 Rancher Desktopを起動

3 起動後、下画像のdockerdを選択しましょう。

これだけで完了です。インストーラーがあると大変助かりますね。

dockerd

docker-compose 使えるようにしたい

(docker-compose持ってない人は)

brew install docker-compose

学が足りてなくて理解できてないですが、
Docker Desktopから乗り換えると、修正が必要な場合があるようです。
下記ファイルのcredsStore を credStore に変えて下さい。

~/.docker/config.json

参考: https://forums.docker.com/t/docker-credential-desktop-exe-executable-file-not-found-in-path-using-wsl2/100225/3

つまづいた部分

mysqlが動かない?

mysql起動時に以下エラーが発生。

chown: changing ownership of '/var/lib/mysql/': Permission denied

dbの永続化に関わるファイル周りの権限がうまくいってない様子。 たぶんvolumeとか一旦全部消した方がいいのかな。

1 以前のdbフォルダ削除
2 volume削除コマンド実施

docker-compose down --rmi all --volumes

3 compose upしたら動きました

initdbが効かない?

compose up時にinitdbが走らないので、 暫定的にcompose.ymlに明示的に書いてあげたら動きました。

        volumes:
            - ./initdb:/docker-entrypoint-initdb.d

redisも動かない?

こちらも上記と同じくcompose up時に発生。

chown: changing ownership of '.': Permission denied

どうにも分からなかったのですが、compose.ymlで明示的にredisバージョンを指定したら動きました。

image: redis:latest から image: redis:2に変更

Rancherが定期的に落ちる?

docker 上げ続けたまま帰ると、次の日こんなエラー吐いて落ちてる。

unexpected EOF

対策:docker 落として帰りましょう。Rancher再起動すると普通に動きます。

おまけ

80portの解放

80番portはデフォでk8s用に使われているので、コンテナしか使わないよって方は 下画像の赤枠部分のチェックを外してあげるとk8s管理コンテナを消せます。

k8s_off

PC起動時にRancherを起動させたい

今日も働くぞー。

docker-compose -p hogehoge up ポチッと
> Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

クソォ。

システム環境設定> ユーザとグループ >「ログイン項目」> ウインドウ下部にある「+」をクリック。 アプリケーションフォルダ内の、自動で起動させたいアプリを選択してクリック。

参考: Macでログインするときに項目を自動的に開く - Apple サポート (日本)

以上。

今回はDocker Desktopの代替としてRancherDesktopを触ってみましたが、
k8sも簡単に作れる様なので軽く触れていきたいなぁと思う次第です。

Casaテックブログを開設しました!

株式会社Casaの開発チームによるブログを開設しました。

弊社は家賃保証という一般の方には馴染みがないけど、実は多くの方に関わりのある事業をしています。

3年くらい前に自分がCasaにジョインした時は事業会社の情シス部門で、現行システムの保守やPCの準備などがメインの仕事で、開発といっても全て社外に委託し、自分も要件の整理といわゆるベンダー管理をしていました。
そこからいろんなバックグラウンドを持つメンバーが集まって社内で開発チームを持ち、ついにはテックブログまで立ち上げられるまでになりました🎉

少しだけ弊社の話を。
Casaでは家賃保証の事業をやっていますが、保証ということにとどまらず、人々の住環境の維持と生活文化の発展への貢献をすることで、豊かな社会にしていくことが企業理念です。その理念のもと、探究心を持って一人一人が成長して夢を実現することを行動規範に掲げています。
不動産というまだまだアナログな業界で弊社のシステム開発が何をしているのか、技術情報の共有、エンジニアの活躍についてこのブログでは書いていければと思います。

写真撮影の時のみマスクを外しています