「深セン」は未来都市なのか?

フォトシンスの@hiroaki_naberunです。

こちらはAkerun Advent Calendar24日目の記事です。 プロダクト部門を管轄しているということで、エンジニアでありませんがアドベントカレンダーに参加させてもらってます。

『未来都市』や『ハードウェアのシリコンバレー』などの輝かしい枕詞と共に語られる中国・広東省・深圳市に先週行ってきた感想を書こうと思います。

ざっくり深センについて

深センは香港のお隣で、日本からは直行便で成田からの直行便が1日1便出ており、フライト時間はわずか4時間半!非常に日本から近い! f:id:photosynth-inc:20191227151742j:plain 安く行くならば香港行きのLCC「香港エクスプレス」で往復2万円ぐらいで香港に行ってからフェリー乗り継ぎがリーズナブルです。

香港との位置関係はこんな感じです。 f:id:photosynth-inc:20191227152140p:plain

深セン珠江デルタの一部として語られることもあります。

珠江デルタ(しゅこうデルタ)あるいは珠江三角洲(しゅこうさんかくす、珠三角、ピン音: Zhūjiāng Sānjiǎozhōu、英語: Pearl River Delta)は、中国珠江河口の広州、香港、深圳市、東莞市、マカオを結ぶ三角地帯を中心とする地域の呼称である。 世界最大の都市圏で、都市圏人口は7,342万人である。(Wikipediaより)

深センはわずか30年前は小さな漁村だったという話がありますが、立地を考えると都市として発展するのは必然だったのかなとも思いました。

未来都市体験

未来都市と語られることのある深センに行ってみて感じた未来都市体験をご紹介したいと思います。 超絶スマホ社会&キャッシュレス社会だなと感じました。

どのお店でもWechat, Alipay払いが基本

店員が専用端末またはスマートフォンで支払いをします。旅行客が現金払いをして、お釣りがなく店舗側が困っている事態もありました。 現地に住んでいる日本人の方に聞いたところ、5年間現金を見たことがないそうです...!

ちなみにVISA、Mastercardなどの国際クレジットカードも利用できませんm( )m(なんて自分勝手な国なんだ

幸いAlipayがTourPassという機能をリリースして、今までは中国国内の銀行口座からしかチャージできなかったものが、国際クレジットカードブランドからチャージ可能になり大きな問題はなかったものの、Alipayが使えなかったらと思うとゾッとします。 f:id:photosynth-inc:20191227171829j:plain

キャッシュレスなのでレジすらない

中国最大のコーヒーチェーン「Luckin Coffee」はレジがなく、全てスマートフォンアプリからオーダーとなります。

しかも3杯以上オーダーすると最寄りの店舗でデリバリーしてくれるので、同僚でコーヒー飲みたい人と一緒にコーヒーを頼めば店舗にわざわざ行く必要もありません。

f:id:photosynth-inc:20191227173830j:plain
Luckin Coffee
全員がスマートフォンを持っている前提の社会ではPOSレジが不要になりえるというのは面白かったです。

他には街中の至るところで「美団外卖」というデリバリーサービスのジャケットを羽織ったおじさんを見かけます。

1食300-400円に対してデリバリーは+100円弱という金額です。

UberEats中国版と思ってもらえれば分かりますが、日本で一番UberEatsの自転車を見かける港区の10倍ぐらいの規模で見かけた気がします。 f:id:photosynth-inc:20191227172443j:plain

現地の企業の人に聞いたところ、高層ビル勤務なビジネスパーソンが多く、昼時になると自分のフロアにデリバリーを呼ぶそうです。

配車アプリのDiDiも充実しています。

町中で呼べばだいたい5分ぐらいで配車されます。

ドライバーは基本的に英語が通じないので、地図で指定したところに確実に届けてくれるDiDiの存在はめちゃありがたかったです。 f:id:photosynth-inc:20191227171507j:plain

すべて中国ベンチャーのサービスというのは気になりますが

深セン滞在中、勝手の分からない街にも関わらず移動も食事もコーヒーブレイクすらアプリ1つで完結してしまうのはめちゃめちゃ便利でした。

日本では人件費が高くて、UberEatsは割高感があったりしますが中国では都市部で働いている人の年収に対してデリバリーサービスが安いので成り立っている状態だなと思います。

この辺りは日本では成立しなく、自動運転の発展などでデリバリーのコストが下がればあり得る世界なのかなと思います。

深センは未来都市なのか?

優れたテクノロジーとは普及コストと提供機能とユーザー体験のバランス

深センでひらすらQRコード決済をしたあとに日本で数日生活してみて、明らかに普段日本で使っているSuica払いの方が支払い体験が正直良かったです。

中国で顔認証が普及し始めている話がありましたが、現在はまだまだQRコードが基本。オフィスでセキュリティの高い一部の企業が顔認証を導入しているのを見かけた程度でした。

普段私たちは支払い体験が最も良いものを求めがちですが、中国で普及しているQRコード決済はどのお店でもすぐにQRコード決済を始められる店舗側導入コストの低さが勝因であり、サービス特性毎のKSFの見極めの重要さを改めて感じました。

日本は課題先進国

深センでは年7-8%程度の人件費の高騰が起き続けているそうです。こうなると当たり前に使っているデリバリーが今ほどリーズナブルに使い勝手良く頼めない可能性があります。

何人かの現地のビジネスパーソンと話をしましたが、掃除の自動化も自動車の自動運転もややピンとこない感覚を持っていて、誰かにその仕事をやらせればいいじゃんという人手不足や労働力確保の課題に気付けていない人がまだまだいたことが印象的でした。

一方で、最近では「996」の炎上問題が中国で起きました。

996とは「朝9時から夜9時まで、週に6日間働く」の意味で中国のIT企業の勤務形態を表現しているらしいのだけど、これに異を唱えた若者の動画が炎上したらしい...

www.jetro.go.jp

現在は労働法に関してはかなり緩いらしいが、日本的な働き方改革がいつ起きてもおかしくないかもしれない。

日本での人手不足対策や労働環境の是正対策の方が未来の都市を表している可能性もあるなと思いました。

最後に

「ハードウェアのシリコンバレー」と呼ばれる所以も垣間見ることができました。

  • ハードウェア特化のアクセラレーターの存在・・・ハードウェア技術者の協力支援や小ロットの製造支援機能まで持っている!

  • 小ロット対応のEMS工場・・・月産100~1,000ロット、場合によってはもっと小ロットでも対応してくれる工場が存在!しかも人件費が日本の1/10だったり、ODMに対応してくれる工場が多数!

  • 華橋北・・・1万店舗以上の電気店・パーツ問屋が存在すると言われ、ODM商品も簡単に入手可能!(本当に使える試作部品を仕入れることができるかは、エンジニアではないので判断付きませんでしたが...)

という3つの機能は素晴らしいな思いまして、こちらも機会があればどこかで紹介したいと思います。

そんな未来都市に出張チャンスもあるフォトシンスでは様々なポジションでエンジニアを募集しております。

recruit.jobcan.jp

Redmine Easy Gannt Plugin でスケジュールの可視化が捗った話

PhotosynthRedmine おじさん @ishturnk です

これはAkerun Advent Calendar12日目の記事です。

f:id:photosynth-inc:20191225114312p:plain

進捗どうですか?

耳が痛いどの組織でも課題になる話題

  • スケジュールの可視化
  • 進捗の更新

について運用してみたメソッドを紹介します

ワークフロー

  • 計画

まずはスケジュールを立てます。

  • 作業→進捗ステータスの更新

仕様作成や実装、評価など、実際の作業を実施します。終わったものには完了のフラグをつけていきます。

  • リリース

開発と評価が終わったのでリリースします。

  • 計画の見直し

ほとんどのケースでは計画通りにはいきません。遅延や前倒しをなど、スケジュールをアップデートします。

計画の可視化と進捗更新ツールに Redmine のEasyGantt をつかってみた

エンジニアは僕は面倒な作業が嫌いなので、

  • ひと目でわかる
  • 更新がしやすい

ツールでなければ、運用が回らなくなります。

Redmineプラグインを導入

こちらのプラグインを導入します。

Redmine Gantt プラグイン - Easy Redmine

使用感については公式の動画をご覧ください。

一部の機能を除き、無料で使えます。(弊社は課金しました)

特徴として、

  • ドラッグ操作でスケジュールの変更(移動や期間)が可能
  • 進捗(%)もドラッグ操作で更新可能
  • 後続チケットをバインドできる(テストは実装の後、など)

実際にチケットにあてはめるとこのようになります。

f:id:photosynth-inc:20191225112031p:plain

見やすくてなかなか良いです。

それでも滞る更新

それでも更新が滞ってしまい、期日を過ぎてしまっているチケットがしばしば。

Redmine おじさんの出番です。

期日が過ぎているチケットをメンション付きで slack 通知する

メールで通知する方法はよく見るのですが、弊社はslackでコミュニケーションをしており、メールだと埋もれがち。 なのでslack通知する方法を実装しました。

// User : user の型
type User struct {
        ID    int    `json:"id"`
        Name  string `json:"name"`
        Login string `json:"login"`
}

// Issue : issueの型
type Issue struct {
        ID      int `json:"id"`
        Project struct {
                ID int `json:"id"`
        } `json:"project"`
        Progress int    `json:"done_ratio"`
        Due      string `json:"due_date"`
        Subject  string `json:"subject"`
        Assign   User   `json:"assigned_to"`
        Status   struct {
                ID int `json:"id"`
        } `json:"status"`
}

// Resp : レスポンス
type Resp struct {
        Issues []Issue `json:"issues"`
        User   User    `json:"user"`
}

func post(message string) {

        type Message struct {
                Username string `json:"username"`
                Icon     string `json:"icon_url"`
                Text     string `json:"text"`
                Linkname int    `json:"link_names"`
                Channel  string `json:"channel"`
        }

        mes := Message{
                Username: "Redmineおじさん",
                Icon:     "http://www.redmine.org/attachments/3462/redmine_fluid_icon.png",
                Text:     message,
                Linkname: 1,
                Channel:  "#投稿チャンネル",
        }
        url := "https://hooks.slack.com/services/XXXXXXXXXXXXXXX"  // webhook url
        payload, _ := json.Marshal(&mes)

        req, err := http.NewRequest(
                "POST",
                url,
                bytes.NewBuffer([]byte(payload)),
        )
        if err != nil {
                return
        }

        // Content-Type 設定
        req.Header.Set("Content-Type", "application/json")

        client := &http.Client{}
        resp, err := client.Do(req)
        if err != nil {
                return
        }
        defer resp.Body.Close()
}

func issues() ([]Issue, error) {
        values := url.Values{}
        values.Add("key", {Redmineのアクセストークン})
        values.Add("tracker_id", {指定するトラッカー})
        values.Add("limit", "100")
        res, err := http.Get("https://{RedmineのURL}/issues.json?" + values.Encode())
        if err != nil {
                log.Fatal(err)
        }
        robots, err := ioutil.ReadAll(res.Body)
        res.Body.Close()
        if err != nil {
                log.Fatal(err)
        }
        var r Resp
        err = json.Unmarshal(robots, &r)
        if err != nil {
                log.Fatal(err)
        }
        fmt.Println(len(r.Issues))
        return r.Issues, err
}

func user(id int) (User, error) {
        values := url.Values{}
        values.Add("key", {Redmineのアクセストークン})
        res, err := http.Get("https://redmine.akerun.com/users/" + strconv.Itoa(id) + ".json?" + values.Encode())
        if err != nil {
                log.Fatal(err)
        }
        robots, err := ioutil.ReadAll(res.Body)
        res.Body.Close()
        if err != nil {
                log.Fatal(err)
        }
        var r Resp
        err = json.Unmarshal(robots, &r)
        if err != nil {
                log.Fatal(err)
        }
        return r.User, err
}

func main() {
        issues, err := issues()
        if err != nil {
                log.Fatal(err)
        }
        fmt.Println(issues)
        now := time.Now()
        str := ""
        for _, s := range issues {
                if s.Project.ID != 4 { // sandbox
                        continue
                }
                if s.Status.ID == 3 { // pending
                        continue
                }
                if s.Progress < 100 {
                        d, err := time.Parse("2006-01-02", s.Due)
                        if err != nil {
                                log.Fatal(err)
                        }
                        if now.After(d) {
                                assign, err := user(s.Assign.ID)
                                mention := assign.Login
                                if err != nil {
                                        continue
                                }
                                str += fmt.Sprintf("@%s\n    %s | %3d%% | %s %s%d\n", mention, s.Due, s.Progress, s.Subject, "https://{RedmineのURL}/issues/", s.ID)
                        }
                }
        }
        if str != "" {
                str = "Redmineおじさんです。チケット更新してね\n" + str
                post(str)
        }
}

やっているのは

  • RedmineAPIでチケット一覧を取得
  • チケットのプロジェクトを指定(フィルタ)
  • チケットのステータスを指定(フィルタ)
  • 進捗が100%になってないもの &$ 期日が過ぎているチケットを抽出
  • チケットのアサインユーザーにメンション通知

という流れです。

Redmine のユーザーとslackユーザーの対応ですが、両者を同じにするという運用をしています。メンションで連携しやすくなるので、slack連携している組織ではおすすめの運用です。

おわり

株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 recruit.jobcan.jp

Akerun Proの購入はこちらから akerun.com

主張と受容、非対称性

Akerun Advent Calendar 2019 - Qiita の25日目の投稿です。 書いたのはeijisakatoです。インフラがメインの技術スタックですが、デザイン、マークアップ、JS以外のところは大体がんばれます。

これを書いた経緯

12月が近くなってから「アドベントカレンダーやるから何か書いて」と怖い先輩からのお達しがあって、当初は入社してしばらく取り組んでいたKubernetesの技術的な話を書こうかなと思っていた。Kubernetesは死ぬほど大変だからやっぱりやめたほうが良さそうという趣旨の下書きを少し作ってみてはみたものの、書いててもどうもピンとこないので別のテーマにすることにした。

僕がPhotosynthにインフラエンジニアとして入社したのは今年の7月のことで、前職での経緯も含めればここ3,4年ほど、技術的なイシューよりは「良いチームや組織」ってどんなものだろうか? ということを、ものすごく重要なテーマとして考えることが増えた。まず当然の前提というか一般論として、「完璧な組織」や誰にとっても都合のよい組織は存在しない。僕は現職の前にも転職は何度かしてきたし、フリーランス時代の経験も含めれば渡り歩いてきた現場は多いほうではないかと思っている。これまでの経験から振り返ってみると、組織で発生する課題というのはいろんな本に書いてあったとおり、いろんな組織で似たような問題が似たような感じで起こっていたと思う。典型的なものではビジネスサイドと開発サイドのコンフリクト、組織の拡大と反比例する開発スピードなど。とはいえ、同じような問題といってもそのディテールは様々であり、全く同じ問題というものもやはり存在しない。

組織において前述のような課題が現場で顕在化してくると、だいたい出てくるのが「もっとコミュケーションをよくしよう」という話だ。そしてそれを改善するためにひねりだされるのは、例えば会議のファシリテートルールだったり人と接するときの標語コレクションみたいなものが多い。でも「コミュニケーションにおいて大事なことをリストアップすべし」などと言われたらそれこそ無限に挙げることができる。相手の話を聴く力やら忍耐力など、「何とか力」のリストを見ると白々しい気分になってくる。ダセェ! 僕はそんな非クールなリストが壁に張り出されるより、もっと単純な指針や心構えで本質的な要点を表現できないかと考えていた。何しろ単純であれば毎日復唱して覚えなくてもいいし、そのことだけを気をつけていればよい。僕のような横着な人間にはピッタリなのだ。

社会的な背景

完全になくなったわけではないにせよ、従来の典型的な組織のヒエラルキーが意味をなさなくなってる状況が増えていて、これはそこら中で言われてることだけど、本当にそうである。

とりあえず我々エンジニア職の仕事を見渡してみるだけでも、技術領域は細分化されそれぞれが果てしない深さを持っており、 自分はある場面ではリードを取れるが、他の場面では完全にフォロワーにならざるを得ないという状況は頻繁に発生している (恐らく他の職種でも多かれ少なかれ、同じようなことは起こっているはずだ)。

エンジニア1人で経営者と要件定義してデザインからマークアップからサーバサイドからインフラを作って保守し続ける人なんてのは、もはや人間ではなさそうにさえ思える。するとチームでの協業は必然となり、長いこと働いていくにはカッティングエッジアーキテクチャより「いろいろやりやすいチームであること」のほうが個人にとって差し迫った命題になってくる。ヘタに上下関係を作るより、それぞれが対等な立場であるほうが余計な人間関係の問題にかかずらわなくてもよくなる。僕が15年ぐらい前に月400時間超えの稼働を達成した案件でやっていた、Windows98端末にActiveXDDLを人力でインストールし続ける経験など、現代のシステム開発においては「へえ、それは大変でしたね!」ぐらいの話題にしかならない。当時の僕は発狂寸前でやっていたが、今はすごくも何ともない。そうすると自動的に「僕ちゃんはエラい人だから威張ってもよい」だの「結構イケてんじゃないか」なんて言ってるヒマは全然なくなる。そんなことを本当に思ってふんぞり返ってたら、またたく間にボコボコにされてしまうだろう。アイデンティティもへったくれもない。

何が言いたいかというと、自分のプレゼンスが良くも悪くも不確かな現代では、誰に対してもフラットな関係を意識的に構築していくことが極めて重要なのである。経営陣やベテランの人に対してもそうだし、入社したばかりの若い人に対してもそうだ。 皆がそれぞれの専門性を持っており、自分のできないことを誰かがやって、誰かができないことを自分がやっている。 そういったフラットな関係性においては、自分はアレができないからなぁとか思う必要は別になくて、みんなそれぞれにリスペクトを持てるように自分のマインドを維持することは健全な精神を保つための死活問題とさえ言える。 でも、先述したように、そういう関係性を作れるための、単純で本質的なコミニュケーションの要点って何なんだろうか?

信頼を作る対話とは何か? 2つのA

人間の意識は大変に矛盾に満ちたもので、昨日にこう思ったとしても今日には全然反対のことを考えているということがよくあるし、 思っていること全てを言語化することはできない。他人の矛盾は指摘したくなるが、自分の矛盾など気づいてもいないか、気づいたとしても理由をこじつけて自分はオールオッケーだと認知的不協和を解消する。また、使った単語や言い回しによっては異なった意味に受け取られたり、思っていることをうまく言えずに議論の場が進んでしまい、それ以降は何もいえなくなってしまうなんてこともよくある。要件を決めていっしょうけんめいに作った機能をレビューすると「あっ、そう意味で言ったんじゃなかったんです」などと言われた日には、全てを投げ出したくなるのはまず間違いない。我々の思考には恐らく限界はないが、使う言葉にはどうがんばっても限界があるのだ。

こういった議論はこれまで、言葉を変えてさんざっぱらなされてきた。そうして大体は「対話を増やそう、フラットに話していこう」といった結論になり、なんとなく結束が強まったような気になって仕切り直しの会議は解散する。その後の経過は言わずもがなだ。でも、対話を増やすとかフラットに話すってのはどういうことなんだろうか。それは、職業はなんですか? とか年収はいくらですか? といった婚活パーティのような質問を延々繰り返したり、「あなたはムカつきます」などといきなり金属バットでぶん殴るような声掛けをすることだろうか。もちろんそんなはずはない。

誰かと話をしていてあまり楽しくなくなってくる場面にはいろいろあるが、自説の主張しかされない、こちらの言い分を聞いてもらえないというのはよくあるケースではないだろうか。そういうケースが続き、自分の話が聞いてもらえないとか言っても無駄だという考え方に行き着くと、自分の身を守ることが他のことより優位になる。すると機能追加の話がきても「知らんけどリソースがありません」と無慈悲に突っぱねることになる。

自分の思っていることを言うには結構な勇気がいる。相手を怒らせやしないかとか、そんなことも知らないの?とバカにされたりする不安もあるし、表現するための適切な語彙を持たず、アワアワ言ってる間に相手に何だこいつと見限られてしまうこともある。

ところが、自分の考えを率直に言ってみる話し手の勇気と、発言を受けいれる聞き手の寛容さがうまく場に揃うと、スッと心が通じたと感じられることがある。そうするとなかなかしめたもので、この野郎と思っていた相手が急にいいヤツに見えてくることだってある。打開策として出てきた案が結局は同じであったとしても、互いに主張をして落としどころをつけたという経過はその後のモチベーションを上げることに大きく影響する。

これをいかにもそれっぽいキーワードに展開してみたとき、僕は Acceptance(受容、受け入れること) と Assertiveness(「自他を尊重した自己表現もしくは自己主張」などと訳される) という単語を思いついた。しかし僕は、もうひとつの何か賢しげに見える、Aから始まる単語を探したいと思ったのだ。もちろんそれは「ポイントは3つあるんです。それは3つのAで始まる・・・」と、まるで本物のMBAホルダーのように言いたいがためである。

3つ目のA

(このエピソードは僕の現職での話ではなく、システム開発の現場でよく見られる典型的な場面という前提で読んでほしい)

経営者とセールス部門やカスタマーサポート部門、システム部門の人たちは抽象的には同じ目標に向かっているはずがが、現実はそれぞれが日々まったく異なる人々や情報に接している。例えば先月に入社したカスタマサポートさんが顧客からの素朴な質問を開発部門に問い合わせると、エンジニアさんは長年の経験から、脳内を一瞬でめぐって出てきた正論をぶっかましたとする。すると大体がカスタマーサポートさんの反発を招くだけに終わる。なぜかといえば、エンジニアさんがその正論を反射的に言えるまでに培った何年もの経験(という言葉に集約されるいろんなこと)を、カスタマーサポートさんは全く知らないからだ。で、その答えが「仕様です」といった極めて短い、愛想もない言葉だったりすると、カスタマーサポートさんはエンジニアさんに殴りかかりたくなるに違いない。

また、経営者が「なんでこんなに人が増えてるのに開発スピードが遅いの?」と首をかしげることが多いのは、成長したシステムはいわばゲームが進んだジェンガのようなもので、上に新しいブロックを置くことも難しくなるし、下にあるブロックを抜いたり入れ替えたりするなんてことはそれこそ一巻の終わりになりかねないという、システム開発の宿命を肉体的な実感として理解することが難しいからだ。DELETE文をターミナルに貼り付けてEnterキーを叩くまでの葛藤を、僕はゼヒ色んな人に体験してほしい。話が逸れたが、時間がかかるのは恐ろしく慎重にならざるをえないからで、そのスピードを上げるために必要なのは何のことはない、単に経験が長いといった身も蓋もないことだったり、何年も経ったシステムを入社3ヶ月のメンバが攻略するのは実に果てしない戦いなのだ。ジェンガの話はどこかで聞いた話の受け売りである。

つまりAさんとBさんの脳内には情報の非対称性(Asymmetry)があって、我々はその非対称性を埋めるように言葉を選ぶべきなのだ。この考えに至ったとき、僕はこれだ!と膝を叩いた。そういったわけで僕は Assertiveness,Acceptance,Asymmetry という3つのキーワードの頭文字を繋げて「3A原則」と名付け、ひとりで喜んでいた。今回の転職活動では面接に行くたびにここぞとばかりに使っていたのは言うまでもないが、評価してもらえたのかどうかはよく知らない。変な人と思われていたかもしれない。

3A原則とは単なる言葉遊びである

でも実際のところ、3A原則というのは単なる言葉遊びやMBAごっこに過ぎない。

「真にフラットな組織(とかいうものがあると仮定して)」は恐らく、参加する全員が成熟した精神を持っていることを前提としている。なぜなら、何を言われても怒ったりムカついたらダメなのだ。そんなのははっきりいって単なるファンタジーである。僕はふざけたことを言われると、何より真っ先に怒りを感じるタイプだ。ただし顔には出さないようにしている。

信頼を築くために我々がやるべきことは結局のところ、対話を積み重ねるといったような新しくも何ともないキーワードに行き着く。これは見方を変えれば、普遍的な課題であると同時に永遠に解決されない課題だとも言える。経験や挫折を重ねて神髄にようやく行き着いたと思ったら棺桶に入っていたということも、昔から綿々と続いてきたことだろう。他者との間で信頼を作れたと実感できるまでには、例外もあるが概してとても時間がかかるものだ。しかし時間をかけて組織における信頼を構築するのは結構だが、何がトレードオフになるか・・・スピードだ! 致命的な犠牲だという他ない。

その人がどういう人かというのは、その人が昨日言ったこと、今日に言ったこと、明日に言ったことの連続においてようやく分かってくる。お仕着せの1on1をしたその1時間の中だけで判断されるべきではない。こんなのは当たり前のことだが、現実的には会社組織において当然のように行われている。なぜなら時間がもったいないのでコミュニケーションは手っ取り早く効率的に行わないといけないからだ。クロージングを意識せずに長々としゃべってると社長に怒られるぞ! でも、しょうもない話をするのもまた楽しいですね。

つまるところ、経営スピードと組織の信頼構築のうち、我々はどちらを優先すべきだろうか? もちろん、何かを選ぶということは他の何かを選ばないことである。しかし僕はこの問いに対して明確な答えを持っていない。僕は結局のところ経営者ではなく、会社員(というか、資本家の対極の存在として)の論理しか持ちえない。どちらかといえば後者なんだけど、そうは問屋が卸さないこともまた真実だ。そういうアンビバレンスには答えがないというのが正解なのだが、しかし一方で、論理が対極にあるとしても互いに信頼が構築されていれば、あまり難しく考えてアレコレ対策をしなくとも幸福な組織が少しずつできていくんじゃないかとも思う。

どこに住んでるの? とかあそこの唐揚げ定食おいしいよね? という話はそれはそれで楽しいものだが、ときにはその人が重要にしている価値観について直接切り込んで聞いてみるのも、とても楽しいと思う。信頼というのは、自分のことを受け入れてもらえたとか、この人は信頼できる条件を満たしたと思ったときにだけ作られるのではなく、自分が相手を受け入れたときにも作られる。つまり、不完全な存在に過ぎない相手を信頼するということを、同様に不完全な存在である自分が選択するのだ。

エンジニアリングで出社を感動体験にする 〜 iOSのオートメーション機能とBluetooth 〜

iOS13から新たにショートカットアプリに「オートメーション」が追加されました。

www.apple.com

オートメーション
トリガーを設定し、あらゆるショートカットを自動で実行できます。

トリガー

トリガーとしては、以下が使用できるようです。

機内モード
アラーム
CarPlay
おやすみモード
低電力モード
Appを開く
Watchワークアウト

ちょっと違いますね。

NFC

NFCを読み取ると実行できるというもの。すごく良さげなのですが、iPhoneX以降じゃないとだめなようです。 私はiPhone7でNFC対応端末なのですが、残念ながら動作せず(候補に出てきません)

到着

位置情報です。家なら良いですが、15Fにある弊社ビルだと位置情報だとちょっと。。。

時刻

出社時間はフレックス。

Wi-FI

候補上位です。しかし、Wi-Fiだと結構遠くから掴んじゃうんです。エレベターの中とか。

Bluetooth

今回はこれにしました。

オートメーションを実行するためにiPhoneBluetooth接続する

RaspberryPi から iPhoheに接続できるようにします。

環境

pi@raspberrypi:~ $ sudo apt-get install bluetooth bluez pi-bluetooth
pi@raspberrypi:~ $ sudo apt-get install gnome-bluetooth

gnome-bluetoothが入ってないと通信に失敗することがありました

 sudo apt-get install expect

bluetoothと関係ないですが、使用するbluetoothctlが対話形式のプログラムなので、expectでスクリプト化しました。

下準備

事前にペアリングします。

  1. scanして対象のmacアドレスを確認
  2. 対象をしてして pair(ここでiPhone側もペアリングを受諾します)
  3. ホワイトリストにいれるため trust
pi@raspberrypi:~ $ bluetoothctl
Agent registered

[bluetooth]# scan on

Discovery started
[NEW] Device XX:XX:XX:XX:XX:XX iphoneの名前

[bluetooth]# pair XX:XX:XX:XX:XX:XX

Attempting to pair with XX:XX:XX:XX:XX:XX
[CHG] Device XX:XX:XX:XX:XX:XX Connected: yes
Request confirmation
[agent] Confirm passkey XXXXXX (yes/no): yes

[bluetooth]# trust XX:XX:XX:XX:XX:XX

[CHG] Device XX:XX:XX:XX:XX:XX Trusted: yes
Changing XX:XX:XX:XX:XX:XX trust succeeded

iPhoneに接続してすぐに切断するスクリプト

前述したように、bluetoothctl が対話型なので expectを使います。 macアドレスはペアリングで使ったものを使用します。

#!/bin/sh

expect -c "
set timeout 5000
spawn /usr/bin/bluetoothctl
expect \"bluetooth\"
send \"connect XX:XX:XX:XX:XX:XX\n\"
expect \"Connection successful\"
sleep 3
send \"disconnect XX:XX:XX:XX:XX:XX\n\"
expect \"Successful disconnected\"
send \"quit\n\"
"

実行するショートカット

Akerunを開けるショートカット

APIでAkerunを開けることができます。出社してまずやること。

developers.akerun.com

音楽をかける

弊社では会社のBGMにSpotifyを使っています。出社したら再生。

developer.spotify.com

新しいツイートを作成

出社なう

体験として

RaspberryPiを置く場所や電波強度を調整することで、接続エリアを限定することができます。

これまで位置情報くらいでしかできなかったことが、柔軟に実現できます。接続する条件がプログラマブルである環境を手軽につくれるのはとても良い :D

盲点

Bluetooth接続をトリガーにする場合は確認メッセージをスキップできませんでした。。。

f:id:photosynth-inc:20191224224527j:plain:w300

おわり

株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 recruit.jobcan.jp

Akerun Proの購入はこちらから akerun.com

第二種電気工事士をみんなで受験した話

この記事は Akerun Advent Calendar 2019 - Qiita の22日目の記事です。

どうも、低レイヤにも興味のあるRoRエンジニアのdaikw - Qiita です。

今日は、弊社エンジニア数人で資格の勉強をした話をします。

Akerunコントローラ

弊社は、鍵をいい感じにクラウド化するためのプロダクトをいくつか提供しています。

その中に、電気錠もAkerun対応させることができる、Akerunコントローラというのがあります。

jp.techcrunch.com

こやつ、実はなかなかに便利でして、サムターン以外のスイッチングは、だいたいなんでも任せられます。ファームウェアをいじればこんなことも…

akerun.hateblo.jp

ただしちゃんとした電源を準備しなければならないので、設置場所の配電状況によって電気工事が必要な場合があります。 現在は電気工事業者さんにお願いして、同行していただいています(お客さんに予め工事しておいていただいている場合もあります)。

電気工事士

前節のように、事業者として電気工事を行うには、電気工事士という国家資格を取得する必要があります。

電気工事士 - Wikipedia

電気工事士(でんきこうじし)は、第一種電気工事士第二種電気工事士とがある。それぞれ自家用電気工作物または一般用電気工作物の工事に関する専門的な知識と技能を有するものに都道府県知事により与えられる資格である。 電気工事士法の定めにより、原則として電気工事士の免状を受けているものでない限り、一般用電気工作物および500kW未満の自家用電気工作物の工事に従事することはできない。

資格未取得者が自宅の電源タップを改造して三相交流電動機を取り付けて漏電事故とかさせてもお上にバレなければ大丈夫だとは思いますが、事業者としては電気工事に従じることはできない定めです。

そこで、コントローラの設置業務に役立ちそうなこの資格をみんなで持っておこうということになりました。

令和元年に第二種電気工事士を受験した狂ったメンバーを紹介するぜ!

  • webエンジニア 1名(daikw - Qiita
  • メカジニア 1名
  • ファーム&エレキエンジニア 1名

準備

www.xn--3kqu6wf5d.com

一応国家資格なので、それなりにちゃんと勉強しないとね、ということで準備しました。

まず教本。ほとんどのページが挿絵になっている雑誌ですが、筆記・技能で一冊ずつ購入。

ぜんぶ絵で見て覚える第2種電気工事士筆記試験すいーっと合格(2019年版)

ぜんぶ絵で見て覚える第2種電気工事士筆記試験すいーっと合格(2019年版)

さらに工具(人数分)と、実際に試験で配られる部品と同等の製品を購入しました。

この時点でもう楽しいですね。初めて見る部品とか楽しくてしょうがないですね。

勉強の仕方

ホーザン株式会社という工具メーカーが運営しているyoutubeチャンネルが声の可愛い女の子が解説しているのでモチベーションが保ちやすくとてもわかりやすく、お世話になりました。

www.youtube.com

筆記も技能もどちらも解説していますが、どちらもお勧めできます。勉強量の目安ですが、私はそれぞれ1週間毎日1~2時間くらいは勉強しました。合計で20~30時間程度やっておけば安心かなと思います。

特に注意すべきところ

筆記は過去問ヒット率がめちゃくちゃ高いので、自動車教習所と同じ感覚で大丈夫です。

一方で技能はやばいです。欠陥が一つでもあれば失格になります。

複線図を書くのは2、3問やればサクッとやれると思います。工作も2、3個やればなんとなく大丈夫な感じがします。 しかし、技能試験は落とすためにあるようで、重大欠陥が一つでもあれば不合格になります。満点を取らねば(ほぼほぼ)不合格の、かなり神経を使うテストです(なので、工作はたくさんやっておくのが良いと思います。僕は試験対策として10問くらい解いておきました)。

denkikoujishi-shikaku.com 電気工事士技能試験(第一種・第二種)欠陥の判断基準

結果

弊社エンジニア、時間のない中奮闘しました。

engineer 筆記 技能
web pass pass
メカ pass pass
エレキ pass fail

全員サクッと合格、というわけには行かなかったですが、気をつけるべきポイントがよくわかりました。 社内で、電気工事士勉強法のレクチャーなども行える形になりました。

免状の取得

とても安っぽいですが、居住地の神奈川で免状申請をして、無事取得できました。 こうして晴れて顧客の現場で設置業務を担当できるwebエンジニアになりました。

f:id:photosynth-inc:20191220165803j:plain:w300f:id:photosynth-inc:20191220165814j:plain:w300

最後に

今後、設置業務に役立ったら、また記事にしようと思います。

参考資料

コントローラのカタログスペックはサポートページに書いてあります。 support.akerun.com

電気工事士の勉強法のレクチャー依頼ははてブコメントまで。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 recruit.jobcan.jp

Akerun Proの購入はこちらから akerun.com

Akerunコントローラーで普通のドアを自動ドアにしたらめちゃめちゃ快適だった

これはAkerun Advent Calendar21日目の記事です。

f:id:photosynth-inc:20191221182301p:plain

はじめに

Akerunハッカーのishturkです。弊社のエンジニアはAkerunを使ったライフハックが大好きで、これまで

  • トーストを焼いたり

akerun.hateblo.jp

  • コーヒーを挽いたり

akerun.hateblo.jp

暮らしに役立つ(?)ハックをやってきました。

新製品が出た!

今年、Akerunコントローラーという新しい製品がリリースされました!

akerun.com

物理的にサムターンを回すタイプだったAkerun Pro に対して、Akerun コントローラーは、電気信号を制御することができます。

技術仕様をもうすこし

エンジニアブログなので少し詳しく書いてみます。

対応する電気錠

  • 通電時施錠型電気錠
  • 通電時解錠型電気錠
  • 瞬時通電型電気錠
  • モーター式電気錠
  • 電磁式電気錠
  • 自動ドア

電気信号のI/O対応

  • DC24V の出力ON・OFF制御(連続・パルス)

電気錠を制御するためです。電気錠コントローラーから電圧を印加するタイプの電気錠で使います。

  • DC24V の出力ON時の極性反転

モーター式の場合は極性を反転することで正転・逆転を制御します。

  • 無電圧接点入力

ボタンや人感センサ、火災報知器などの外部機器の入力に使います。

  • 無電圧接点出力

接点入力に対応した機器を制御するために使用します。自動ドアとか。出力はパルスです。

さて、何をハックしようか。。。

Akerunハッカーとしては、新製品が出たからには、何もしないわけにはいきません。

ただ困ったことに、前述のように様々な電気信号の入出力に対応しているので、 電化製品は何でも制御できてしまうのではないでしょうか。

Akerunならではのテーマにしよう

Akerunは入退室管理ができるソリューションです。ここはやはり「入退室」をするときに連携できる機器をハックすることにします。

入退室するときに連動してほしい機器は何があるでしょうか。

  • 照明
  • 音楽
  • テレビ
  • 空調

いろいろあると思います。ですが、鍵を開けたら自動的にドアも開いてほしくないですか?

Akerunコントローラーでドアも自動化してみた

※ Akerunコントローラーのソフトウェアをカスタムしています。通常仕様の製品では連動できません。

今回は RYOBIさんが出しているRUCADを使います。 ドアを軽く押すと自動で開け閉めしてくれる優れもの。接点入力にも対応しています。

設置

Akerunコントローラーと電気錠、RUCADをそれぞれ接続します。

f:id:photosynth-inc:20191221171335p:plain

うごいたっ

f:id:photosynth-inc:20191221180946g:plain

めちゃめちゃ快適でした。いままでドアを開けるという行為にどれだけ消耗していたのかがわかりました。

おわり

今回は、ドアを開けるという原点に戻ってハックしてみました。AkerunはIoTプロダクトなので、

  • API連携
  • ハードウェア連携

のどちらもできてしまうのが最大の強みです。

つながるモノづくりで感動体験を未来に組み込む。開発者としては、とてもとても面白い職場です。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 recruit.jobcan.jp

Akerun Proの購入はこちらから akerun.com

Web Bluetooth からAkerunを操作する

この記事はAkerun Advent Calendar 20日目の記事です。

今回はファームウェアエンジニア いとう が担当です。今回はWeb Bluetoothでウェブエンジニアデビューします。目指せフルスタック!

目的

今月行われたエンジニア日帰り合宿での出来事です

誰か 「Akerunの初期設定、スマホ持ってなかったりPCに専用アプリインストールできないお客様もいる。どうしようか?」

私 「Web Bluetoothでブラウザだけで設定できればよくね?(ウェブエンジニア賢い人多そうだからサクッと作ってくれそう)」

誰か「ほな、お前やってな」

私 「・・・」

Web Bluetooth

無茶振りされましたがWeb Bluetoothなんてqiitaで何度か記事を目にしただけで海のものとも山のものともついてない私です。仕様書はここみたいです。

設定

色々な Web Bluetooth記事をみていると必ず https接続が必要!と書いてあります。まずは環境を用意することにしました。

serveo

私はサーバーとか何にもわかりませんのでSlackに流れていたローカルファイルをhttpsで公開できるserveoを使ってみます。

http://serveo.net/

f:id:photosynth-inc:20191220012449p:plain

死んどる・・・(2019年12月20日現在serveoはダウンしていうようです)

ngrok

改めて弊社の優秀なウェブエンジニアーズに聞いたところ ngrok が良さげだったのでここを参考にインストールします。ngrokはスムーズにインストール&登録できました。

nginx

ngrokさえインストールできればローカル環境でウェブサーバーを立てれば準備完了です。macOSのシステム環境設定の共有からWeb共有を有効にしま・・・・え!?ない!。随分前からWeb共有はなくなっているようです。歳はとりたくないですね。

ということでqiitaの記事にもあるようにnginxをインストールしてみましょう。

brew install nginx
nginx

上記だけで可能とのことでしたが3つほどつまずきました。

  • インストール時に権限関連で怒られる
    • brewのエラーに解決方法でてますのでその通りに実施してOK
  • 実行時にnginx: [emerg] mkdir() "/usr/local/var/run/nginx/client_body_temp" failed (2: No such file or directory)と怒られる
  • 実行時にnginx: [warn] 1024 worker_connections exceed open file resource limit: 256と怒られる

それではngrokを起動してみましょう

./ngrok http 8080
ngrok by @inconshreveable                                                                                            (Ctrl+C to quit)
                                                                                                                                     
Session Status                online                                                                                                 
Account                       waiwai@supaahakaa.co.jp (Plan: Free)                                                                   
Version                       2.3.35                                                                                                 
Region                        United States (us)                                                                                     
Web Interface                 http://127.0.0.1:4040                                                                                  
Forwarding                    http://xxxxxxxx.ngrok.io -> http://localhost:8080                                                      
Forwarding                    https://xxxxxxxx.ngrok.io -> http://localhost:8080                                                     
                                                                                                                                     
Connections                   ttl     opn     rt1     rt5     p50     p90                                                            
                              0       0       0.00    0.00    0.00    0.00        

このhttps://xxxxxxxx.ngrok.ioにアクセスすると・・・

f:id:photosynth-inc:20191220020520p:plain

あれ?だめです。結論から言うと下記のコマンドでないと動きませんでした。何故かはイマイチわかってません。

./ngrok http -host-header=rewirte 127.0.0.1:8080

これでようやくhttps接続でローカルファイルを公開できるようになりました!

結局

ここまでhttps接続環境を揃えてスクリプトをしこしこ書いていたのですが、検証のためhttps接続でなければどのようなエラーとなるのかを確認したくFinderからChromeにindex.htmlをDnDすると・・・動くやん!誰やhttpsいるっていうたん!というわけで2019年12月20日現在はhttps接続は必須ではないようです。(後述:Windows環境では必須でした)

処女作

これで私もフロントエンドエンジニアデビュー。長編大作のhtmlファイルです。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Akerun web door sensor</title>
    <script src="akerun.js"></script>
  </head>
  <body>
    <button id="close">Close</button>
  </body>
</html>

JavaScriptです。今回はAkerun付属ドアセンサーの通信を模してみました。(セキュリティ処理を外した特別なファームウェアをAkerun側に書き込んでいます。皆様がご利用のAkerunは下記の処理では動作したりしません。念の為)

var Akerun = function() {};

Akerun.prototype = {
  // AKerun
  AKERUN_SERVICE_UUID: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  UUID_AKERUN_RX: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",

  close: function() {
    navigator.bluetooth
      .requestDevice({
        filters: [{ namePrefix: "akerun_******xx" }],
        optionalServices: [this.AKERUN_SERVICE_UUID]
      })
      .then(device => {
        console.log("device", device);
        return device.gatt.connect();
      })
      .then(server => {
        console.log("server", server);
        return server.getPrimaryService(this.AKERUN_SERVICE_UUID);
      })
      .then(service => {
        console.log("service", service);
        return service.getCharacteristic(this.UUID_AKERUN_RX);
      })
      .then(chara => {
        var buffer = new Uint8Array(xxx);
        buffer[0] = CMD_0;
        buffer[1] = CMD_1;
        buffer[2] = CMD_2;
        buffer[3] = CMD_3;
        // 中略
        buffer[xxx-1] = CMD_XXX;
        chara.writeValue(buffer);
        console.log("Akerun:", chara);
      })
      .catch(error => {
        console.log(error);
      });
  }
};

window.onload = function() {
  var akerun = new Akerun();
  document
    .getElementById("close")
    .addEventListener("click", akerun.close.bind(akerun), false);
};

結果

f:id:photosynth-inc:20191220121624g:plain

  • BLE通信はすんなりできたのでAkerunの初期設定ぐらいであれば十分可能
  • ただしJavaScriptコードが丸見えなのでセキュアな仕組みを別途構築する必要がある
    • 初期設定限定で以降は口を閉じるような仕組み?
  • 実運用では環境の縛りキツい

    • Chrome縛り
    • PCに詳しくないユーザーはPCにBLE搭載しているかどうか判断できなさそうでサポートが難しい
  • JavaScript完全に理解した

2019年12月20日追記

  • Windowsから実行するときにはchrome://flags/#enable-experimental-web-platform-featuresのフラグを有効にしてもらわないといけない
    • このフラグへのURLはリンククリックでもセキュリティのため遷移しないのでまず一般ユーザーに使ってもらうのは厳しいでしょう
    • 将来に期待

参考にしたサイト

2019年12月20日追記、編集

  • みられたくないところが伏せ字にしきれてなかったコードを微修正
  • Windowsでの制約を追記
    • macOS上はごくごく普通に動くのに・・・

・・・

株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 recruit.jobcan.jp

Akerun Proの購入はこちらから akerun.com