dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

UoPeople入学前に知っておくと良かった5つのこと

この記事は 社会人学生 Advent Calendar 2024 6日目の記事です。

こんにちは。@zaki___yama と申します。
私は普段 Web エンジニアとして働く傍ら、2021年頃から University of the People (UoPeople) というオンラインの大学に通っています。
今も細々と続けています。3年近く経ちますが休み休みやってるので、受講した科目は10もないぐらいです。

UoPeople に入学した動機はシンプルに、コンピュータサイエンスの基礎的な知識を学び直したいと思ったからです。
興味のある分野を独学で学ぶことも考えたのですが、カリキュラムという形で一定網羅的な内容が学べると期待したこと、また学んだ成果が学位という形で得られることも一定魅力に感じ、無理なら途中でやめればいいやと飛び込んでみることにしたのでした。

一方、事前にいくつかの大学を比較はしたものの、UoPeople には勢いで決めてしまった面もありました。
そのため、後々になって「えっ、そういう制度になってるの?」と知るようなことも多々ありました。

この記事では、主に UoPeople への入学を検討している方向けに、最初に知っておくと良かったなあと個人的に感じた点をいくつか共有します。
講義の内容には触れておらず、UoPeople という大学そのものの制度面の話です。

なお、私自身は今期単位を逃すと退学かもしれないというところまで追い込まれています。(2. 休学について を参照)

1. Tuition-Free = 完全無料、ではない

大学の Web サイト を見ると、いろんなところで「Tuition-free」を謳っています。
日本語に訳すと「授業料無料」でしょうか。

ただ、完全に無料で講義が受けられるわけではありません。
1個科目を受講するのにつき、受講後に assessment fee というのを支払う必要があります。

詳しくはこのページに記載があります。

学士の場合、1科目あたりの assessment fee は $140
(あれ、これまで支払ってるのは $120 だけどな...)
またトータルでかかるコストはだいたい $5,660 ぐらいだよと書かれています。

そしてもうひとつ注意点としては、単位を取得したかどうかによらず、最後まで受講した科目については assessment fee を払わなければなりません。支払わないと次の学期(term)の履修登録ができません(たしか)。
ですので、「私は学位取得は別に求めてないから、興味ある科目だけタダで履修しよ〜」というのは基本的にできません。

2. 休学について

参考:Inactivity - uopeople catalog

UoPeople では1年を5つの学期に分割しています。ある学期で1つも科目を受講しなかった場合、休学扱いになります。
また、連続して5学期以上休学した場合、退学 になります。

UoPeople allows students to be inactive for up to five (5) consecutive terms but not inactive for more than five (5) terms.

(more than だから5学期分まではOK、かな?)

明示的に休学することを選んだ場合に加え、普通に単位落としてその学期の単位が0、という場合も休学扱いになるので注意です。

3. 大学に在籍できる最長期間

参考:Academic Degree Requirements - uopeople catalog

Complete all requirements for the Bachelor’s Degree in no more than 50 terms of active enrollment excluding any periods of separation from the University.

50学期のうちにすべての単位を取得し終える必要があります。
ただし、「50 terms of active enrollment」とあるので、2で言及した休学期間は含まれません。

4. 科目のDropとWithdrawとFail

参考:Course Drops and Withdrawals - uopeople catalog

UoPeople では、学期が始まった後も科目の履修をキャンセルできる猶予期間が設けられています。
具体的には、

  • 学期開始〜最初の週までにキャンセル:Drop
  • 学期開始〜4週目までにキャンセル:Withdraw

というように呼び方が違います。

両者は、成績証明書にキャンセルしたことが記録されるかどうかの違いのようです。Drop は記載されませんが、Withdraw の場合は "W" と記録されます。
が、どちらも全体の成績には加味されません。

5週目以降になってしまうと、科目のキャンセルはできません。
加えて、そのまま単位を落としても assessment fee は支払う必要があるため、死ぬ気で単位を取る必要があります。

5. 履修する科目は自由に選択できない

これは私が在籍中に制度がいつの間にか変わった点です。Learning Pathway などと呼ばれています。

以前は科目ごとの Prerequisites(その科目を履修するために単位が必要な別の科目)を満たしてさえいれば、履修する科目は自由に選ぶことができました。

その仕様が途中から変更になり、現在は システムが指定した順番で科目を履修する必要があります。
ここには一般教養系の科目も散りばめられているため、「一旦興味のある CS 系科目を履修して、最後までいけたら学位取得を目指して一般教養などの科目も取りに行く」といった戦略がとれなくなりました。

正直、これで心折れそうになっています。

なお、CS の学士はこちらに Pathway が記載されています。
Bachelor of Science in Computer Science (BS-CS) - uopeople catalog

おまけ:UoPeople ぶっちゃけ続けられそうなのかという話

最後に、UoPeople に入学してみて今どう感じているのか、という率直な感想を。

正直に言うと払ってる金額に見合ってるのかなあとか、卒業まで続けられるか微妙だなあとは思っています。

その理由としては、1つは「5. 履修する科目は自由に選択できない」で言及したように自分で履修する科目を選べなくなったことが大きいです。
忙しい中でせめて興味ある CS 系の科目を受けたいのに、一般教養科目を強いられるというのは苦痛でしかない。

また、教材の質については他と比較してないのでなんとも言えませんが、課題についてはディスカッションや自身の考えを述べる系のものが中心で、教材の内容を問うものではないことが多いです。
個人的には、教材の内容をちゃんと理解しているか、といった観点で課題を出してくれたほうがうれしかったりします。

こちらの方が書いている内容は非常に共感できます。。。

おわりに

というわけで UoPeople の制度面の話を中心に、最初に知っておくと良さそうなことを紹介しました。
本格的に検討される際は、カタログに目を通すことをおすすめします。

最近だと、このカタログを PDF でダウンロードして ChatGPT に食わせれば、日本語であれこれ質問できるので便利です。

「論理が伝わる 世界標準の「書く技術」」を読んでパラグラフ・ライティングを学んだ

読みました。

読んだのは4月頃だったけどアウトプットをずっと放置してた。。。
いい本でした。

背景:ドキュメント書いてるときの個人的お悩み

社内のドキュメントやブログを書いているとき、たびたび

文章ってどこで区切ったらいいの?
なんとなく長くなったら改行入れたくなるけど…

みたいな気持ちになっていた。そのことを、テクニカルライター系の職種をやっている前職同僚に話したらこの本を勧めてもらった。

本書の目次

第1部  なぜ伝わらない、どうすればいい
  1  伝わらない文章がいっぱい
  2  なぜパラグラフなのか
  3  分かりやすさの基礎
第2部  パラグラフで書く
  1  総論のパラグラフで始める
  2  1つのトピックだけを述べる
  3  要約文で始める
  4  補足情報で補強する
  5  パラグラフを接続する
  6  パラグラフを揃えて表現する
  7  既知から未知の流れでつなぐ
第3部  ビジネス実践例
  1  通知文
  2  技術レポート
  3  社外文書

第2部まででパラグラフライティングの書き方については紹介が終わっており、ここまで約180ページ。
第3部はこれまでに学んだことを活かしての実践例(まだ読んでない)。

なので、第2部までならかなりさらっと読めると思う。

書籍の内容紹介

本書はタイトルの通り、パラグラフ・ライティングとは何か、なぜパラグラフで書くべきなのか、に加え、書くための具体的なテクニックについて紹介されている。

パラグラフとは何か

  • 1つのトピックを説明した文の集まりのこと
  • 原則として、1つの要約文と、複数の補足情報の文で構成する
  • さらに、各章は総論のパラグラフではじめる
  • ので、文章全体の構成としてはこんな感じになるはず

欧米では「アカデミック・ライティング」などの科目で大学1年生までにみっちり学ぶ、らしい。

「段落」との違い

  • 似ているが、パラグラフは「1トピック限定で、要約文がある」というところが違う
  • 段落は「①長い文章中の大きな切れ目。段。②転じて、物事のくぎり」(広辞苑(第6版 岩波書店))なので、そのような明確な決まりはない

パラグラフで書くと何がうれしいのか

  • ロジックの構成単位とレイアウトの固まりが一致するため、文章が論理的になり、読みやすくなる
  • 速読できる(読み飛ばしやすくなる)
    • なぜなら、冒頭の要約文を読んで理解できたら後半は読む必要がなくなるから

(p.78)
実は、飛ばし読みした方が、重要な情報が記憶に残ります

それな

面白いのは、この本自体が一貫してパラグラフ・ライティングのルールに則って書かれている点。

なので説得力あるし、読みやすい。

(一例として、本書のp.36-37)

そういえば「エンジニアのためのドキュメントライティング」にも「流し読みに適した書き方」という話があった。

(過去に書いたブログ「エンジニアのためのドキュメントライティング」を読んだ - dackdive's blog より)

パラグラフで書くためのルール

本書で紹介されているルールは7つ

  1. 総論のパラグラフで始める
  2. 1つのトピックだけを述べる
  3. 要約文で始める
  4. 補足情報で補強する
  5. パラグラフを接続する
  6. パラグラフを揃えて表現する
  7. 既知から未知の流れでつなぐ

1. 総論のパラグラフで始める

  • 総論のパラグラフがあると読み手はメンタルモデルを形成できる
  • 要約文「いま、業界にはA、B、Cの3つのトレンドがあります」
    • 読み手「なるほど、じゃあこの後は、A、B、Cの話が順番に来るのか」

4. 補足情報で補強する

  • 要約文の用語の説明や、要約文の根拠などを述べる
  • この補足情報まで読めば、読み手全員が要約文に納得するように説明する

5. パラグラフを接続する

  • パラグラフを「縦」と「横」に接続する
  • ロジックの構造と一致させる
  • 縦:ロジックが順番に展開されているとき。総論のスタートAからゴールDまでのキーワードを、各論の要約文でA→Dまでつなぐ
  • 横:ロジックが並列に展開されているとき

6. パラグラフを揃えて表現する

  • 5の横の接続において、文章表現を各論のパラグラフで一致させる

感想

  • パラグラフとは何か、は理解した。し、よさそう
  • 1パラグラフ1トピックにする、パラグラフ同士を接続するときにどういうことに気をつけたらいいか、はまだ具体的なテクニックに落とし込めていない

Q. 業務で活かせそうですか?

わからん

  • 自分は極力箇条書きにしてしまうきらいがある
  • 章ごとに要約パラグラフが必要になるほどの文章そうそうない

ということで、これをそのまま適用できるような文章を書く機会があるかというと…

ただ、パラグラフという考え方は理解したので、自分の文章をセルフレビューするときに
「最初の一行ずつ読んでも内容は伝わるかな?」
というレビュー観点が持てたのはよかった。

あと、結局文章にする前のロジックが大事だなという身も蓋もない感想もある。

気に入った一節

(参考:技術書は気に入った一節を見つけるだけでいい

(p.19)
●読み手に責任転嫁していないか
 伝わらないのは、読み手ではなく、書き手の責任です。
伝わらないことを、読み手の読解力のせいにするのではなく、なぜ伝わらないのかを反省すべきです。

「1.2 勘違いをしていないか」より。ズバッと言い切っていて良い。

また、続く文章には

伝わらなかったことは、文章の質が低いことを示すフィードバックなのです。このフィードバックが文章力を上達させるのです。

とある。

こっちが推敲して書いた文章を汲み取ってもらえないとどうしても読み手のせいにしたい感情が芽生えるけど、自分の書いた文章のどこが悪くてそう読ませてしまったのか?を考えて次に活かすようにしたい。(感情的には難しいけど!)

あわせて読みたい

このブログを書くために情報を整理してたときにこの記事を読んで知った。
良い文章の書き方とコツ、重要スキル:「パラグラフライティング」の解説 #初心者 - Qiita
同じ著者。気になる。

「Webブラウザセキュリティ」の社内輪読会をやった

読みたいなと思って2年近く積読状態だった本を、会社の同僚と一緒に輪読会形式で読んだ。
自分一人じゃ挫折してたと思うので誰かを巻き込んでよかった!

本書の目次

第1章 WebとWebセキュリティ
   1.1 Webを構成する基本の3つのコンポーネント
   1.2 プラットフォームとしてのWeb
   1.3 Webセキュリティ
   1.4 サーバーサイドWebシステムのセキュリティ
   1.5 クライアントサイドWebシステムのセキュリティ
   1.6 まとめ

第2章 Origin を境界とした基本的な機構
   2.1 Webリソース間の論理的な隔離にむけて
   2.2 OriginとSame-Origin Policy(SOP)
   2.3 CORS(Cross-Origin Resource Sharing)
   2.4 CORSを用いないSOPの緩和方法
   2.5 SOPの天敵、XSS(Cross-Site Scripting)
   2.6 CSP(Content Security Policy)
   2.7 Trusted Types
   2.8 まとめ

第3章 Webブラウザのプロセス分離によるセキュリティ
   3.1 Webブラウザが単一のプロセスで動作することの問題
   3.2 プロセスを分離した場合の問題
   3.3 Process-per-Browsing-Instanceモデルに対する攻撃
   3.4 Process-per-Site-Instanceモデルとその補助機能
   3.5 まとめ

第4章 Cookie に関連した機構
   4.1 Cookieの導入の動機
   4.2 属性によるCookieの保護
   4.3 Cookieの性質が引き起こす問題とCookieの今後
   4.4 まとめ

第5章 リソースの完全性と機密性に関連する機構
   5.1 問題と脅威の整理
   5.2 HTTPSとHSTS
   5.3 Mixed Contentと安全でないリクエストのアップグレード
   5.4 Webブラウザが受け取るデータの完全性とSRI
   5.5 Secure Context
   5.6 まとめ

第6章 攻撃手法の発展
   6.1 3種類の攻撃手法
   6.2 CSP下でのXSS
   6.3 Scriptless Attack
   6.4 サイドチャネル攻撃
   6.5 まとめ

第6章は発展的な話題ぽかったのでスキップ。

この本について

今回は輪読会の最後にそこそこ労力をかけて書籍の内容をまとめるという活動をやった。 せっかくなので冒頭の内容をそのままこちらに記載しようと思う。
(ほんとは全部書きたいけど書籍のネタバレになってしまうので控える)


本書の全体像

この書籍は、一貫して

WebブラウザはどのようにしてWebリソース間を適切に隔離(isolation)するか」

について書かれている。

具体的には、

  1. リソース間の論理的な隔離をどう達成するか
  2. リソース間のプロセスレベルの隔離をどう達成するか
  3. Cookieをどうセキュアに取り扱うか
  4. 出入りするリソースの信頼性をどう確保するか

の4つの問題に焦点をあて、第2章〜第5章まで各章ごとにそれぞれのトピックを掘り下げている。

本書の「序文」より引用

なぜ、このような観点を気にする必要があるのか?

1, 2:リソース間の論理的な|プロセスレベルの隔離

  • WebブラウザはさまざまなWebアプリケーションが同時に動作するプラットフォーム
  • 悪意のあるWebページを開いたことで、
    • 同時に開いている別タブの情報が読み出せたら?
    • Webブラウザに保存されているすべての情報(localStorageなど)にアクセスできたら?
    • →ユーザーが受ける被害は甚大
  • そのため、Webブラウザは、自身が取り扱うさまざまなリソース間を適切に隔離する必要がある
  • リソース間の隔離、と言ったときに、論理的な隔離プロセスレベルの隔離に分類して考えることができる
  • 論理的な隔離
    • たとえば「悪意のあるページを開いたときに、別のサービスへのHTTPリクエストが発行され、そのレスポンスの中身にアクセスできる」といったことがあってはならない
    • そのため、ブラウザは「そのリクエストを発行してよいか?」「レスポンスの中身にアクセスできるか?」という形で、論理的な制限を行う必要がある
  • プロセスレベルの隔離
    • たとえば、Webブラウザに任意のコードを実行できる脆弱性があり、悪意のあるページにアクセスしたときにメモリ空間上の任意の位置にある値を読み出せると仮定する
    • すると、攻撃者の罠ページから論理的には読み出せなくても、一度リソースに対してリクエストしてからメモリ空間を直接探索することで、Webリソースを読み出せてしまう
      • →といったことはあってはならない
    • このような問題は、Webブラウザのプロセスが適切に分離されていれば起こらない

3: Cookieのセキュアな取り扱い

  • リソース間の隔離だけではなく、リソースとWebブラウザ内のデータストレージとの隔離も考えなくてはいけない
  • Cookieは、Webブラウザ中に保存されており、かつHTTPリクエストを通して外部に送信されるという特徴がある。そのため、リソースの論理的な隔離、プロセスレベルの隔離に関する議論をそのままCookieにも適用するのは心もとない

4: 出入りするリソースの信頼性

  • ブラウザ内でリソースを隔離できていたとしても、リソースがブラウザに届く前に改ざんしたり盗聴したりできてしまっては意味がない
  • そのため、出入りするリソースの信頼性をどう確保するかにも関心がむけられるべき

各章ごとに学ぶキーワード

  • 2章(Webリソースの論理的な隔離)
    • OriginとSame-Origin Policy(SOP)
    • CORS
    • CSP(Content Security Policy)
    • (おまけ程度に)Trusted Types
  • 3章(Web ブラウザのプロセス分離によるセキュリティ)
    • ブラウザのIsolation Model
    • Site Isolation
    • CORB、CORP、COEP、COOP(ぐへえ)
  • 4章(Cookie
  • 5章 出入りするリソースの信頼性

感想

「本書の全体像」のところにも書いたけど、リソース間を適切に隔離するには?というテーマで一貫しており、かつ章ごとの内容は独立性が高いので気になるトピックだけかいつまんで読むこともできて良かった。

ただ、場所によっては説明が少々難しいと感じる部分があり、そのあたりはMDNなども適宜参照しながら知識を補っていった。

こちらの本も並行して読むとよかったかもしれない。

Same-Origin PolicyだったりCORS、CSRF、CSPのような略語表記の「なんか聞いたことあるけど人に説明できない」系の用語について、なぜそれが必要か?を理解しながら知識を整理できた。数ヶ月後に説明できるかは自信ないが、最後にちゃんとまとめたのでそれが活きると思いたい。

輪読会をやって良かったこと

まず何よりも、誰かと一緒にやることで最後までくじけずにやりきることができたので、同僚氏が誘いに乗っかってくれたのはほんとにありがたかった。わからないところも「うーんわからん!こういうことでは?」って言いながら前に進められたのは良かった。

あとは、CSPなどは特に業務ではあまり意識する機会がなかったせいか、みんな本当に使ってるの?とかイメージしきれない部分があったのだが、そういうときに実世界のユースケースをググってみたり実際のサービスでのリクエストをDevToolで覗いてなるほど〜とかやれたのはワイワイ感あって楽しかった。

CSPの事例でいうとこのあたり。

累積和とは何か、およびABC098 C: Atttentionの解説

を解いていて、「累積和」という概念を知ったのでメモ。

こちらの本の「4.2 階差と累積和」でも紹介されている。

また、すでに

という素晴らしい記事があるので、ここでは累積和についての簡単な説明と、具体例としてABC098のC問題の解き方を紹介。

累積和とは

数列 a = [a_1, a_2, ... a_N] に対して

s_0 = 0  
s_1 = a_1
s_2 = a_1 + a_2
...
s_i = a_1 + a_2 + ... + a_i

つまりi番目までの和をとったものを累積和と呼ぶ。

累積和の何がうれしいのか

「配列の特定の区間の和を求める」ような処理を大量に行うシーンにおいて、
累積和を先に計算しておくことで、求めている計算結果を高速に得られる

ということだと理解した。

もう少し具体的に書くと、数列 a = [a_1, a_2, ... a_N] の l 番目から r 番目までの和を求める場合、O(N) の時間がかかる。

let sum = 0;
for (let i = l; i < r; i++) {
  sum += i;
}

これに対し、累積和を先に求めておくと、l 番目から r 番目までの和は

s[r+1] - s[l]

なので、O(1) で求まる。

なお、累積和の計算は、先頭の要素から順に足し合わせていけばいいので O(N) で求まる。

ABC098 C問題:Attentionを解く

ここで、具体例として冒頭に挙げた問題を考えてみる。

問題文は以下。

N 人の人が東西方向に一列に並んでいます。 それぞれの人は、東または西を向いています。 誰がどの方向を向いているかは長さ N の文字列 S によって与えられます。 西から i 番目に並んでいる人は、S_i = E なら東を、S_i = W なら西を向いています。

あなたは、N 人のうち誰か 1 人をリーダーとして任命します。 そして、リーダー以外の全員に、リーダーの方向を向くように命令します。 このとき、リーダーはどちらの方向を向いていても構いません。

並んでいる人は、向く方向を変えるのを嫌っています。 そのためあなたは、向く方向を変える人数が最小になるようにリーダーを選びたいです。 向く方向を変える人数の最小値を求めてください。

まず、i 番目の人をリーダーに任命した場合、

  • 1〜(i-1)番目までで「西」を向いている人
  • (i+1)〜N番目までで「東」を向いている人

は、それぞれ向く方向を変える必要がある。

これを、iを1番目からN番目までループしつつ計算すると、O(N2)の計算量になってしまう。

そこで、

s_i = 1番目からi番目までで、東(or 西)を向いている人の数の合計

と定義する。

そうすると、i番目の人がリーダーのときの求めたい人数は

1〜(i-1)番目までで「西」を向いている人
-> s_[i-1]


(i+1)〜N番目までで「東」を向いている人
-> (i+1)〜N番目までの人数 - (i+1)〜N番目までで「西」を向いている人
-> (N - i) - (s_N - s_[i])

両者を足し合わせることで導出できる。

以上を Rust で書くと、こんな感じ。

use proconio::{input, marker::Chars};

fn main() {
    input! {
        n: usize,
        mut chars: Chars,
    }

    let mut s = vec![];
    s.push(0);

    // s[i]: 1~i 番までで W を向いている人の数
    let mut count = 0;
    for &ch in &chars {
        if ch == 'W' {
            count += 1;
        }
        s.push(count);
    }

    // i 番目がリーダーだったとき、
    // 1~i-1 番目まで: W を向いている人が向く方向を変える => s[i-1] 人
    // i+1~n 番目まで: E を向いている人が向く方向を変える
    // => W を向いているのが s[n]-s[i] 人
    // => E を向いているのは {n-(i+1)+1} - (s[n]-s[i])
    let mut ans = n;
    for i in 1..=n {
        let target_num = s[i - 1] + n - i - (s[n] - s[i]);
        if ans > target_num {
            ans = target_num;
        }
    }
    println!("{}", ans);
}

おわりに

愚直に計算するとタイムアウトになっちゃいそうだなーというときに使えそうなテクニック。
ただし、わかっていても何を累積和として計算しておくか、が閃かないと難しそう。

冒頭で記載した Qiita の記事には他の過去問も紹介されてたので、何個か解いてみるとコツがつかめるかなー。

「ヘルプセンターを支える技術 ── 生成AI時代の自己解決エンジニアリング」に参加したメモ

行ってきた。

メルカリのヘルプセンター内製化:自己解決率向上とCPT削減への挑戦

(ちょっと遅れて参加)

  • CSディビジョンが目指すこと
    • Effortless Customer Experience
    • 問い合わせること
    • JR CS Engineering
      • Help Center ← 登壇者はここに所属
      • Contact Center
  • Help Center Teamが追い求める指標
    • 自己解決率
      • CPT (Contact Per Transaction) 問い合わせ数
      • 取引数を分母にして割ることで、ユーザー増加しても一定の数値にする
    • AHT (Average Handling Time) 🤔定義聞き逃した
      • 想定ガイド閲覧率
  • Help Center大幅リニューアル (2022年)
    • アプリやWebそれぞれに問い合わせフォームがあり、それぞれの開発チームがオーナーだった
    • ガイドごとに、それにひもづいたフォーム
  • Skill Base Routing
    • フォームごとにtypeが設定されてる
    • Primary Queue
      • SkillごとにQueueが建てられ、入信順にお問い合わせが並ぶ
    • Site Queue
      • Skill A はコンタクトセンターAに40%、Bに40%、…となるよう差配される
    • 🤔Skillとはコンタクトセンターの人員の能力?
  • 内製化の利点1:Data Drivenな改善サイクル
    • A/Bテストの共通プラットフォームがある
  • 内製化の利点2:Personalization
    • 問い合わせ前に購入した商品を選ばせる。そのためにメルカリのAPIと連携する
  • Help Center Platforming
    • 課題:新規ビジネスを立ち上げるたびにHelp Centerを作っている
    • 今後:内製Help CenterをPlatf

自己解決を支える検索技術と改善サイクル

Helpfeel CTO akiroom

  • Helpfeelのアルゴリズム「意図展開」
    • 登山のメタファー
    • 例:商品の返品方法 というゴールに対し、入口(登山道)はさまざま
  • 伊予銀行の事例「ハンコ なくしちゃった」
  • 曖昧検索
    • asearch
      • タイポなどを吸収
    • 意図予測検索2
      • 意図展開したデータを元にベクトル検索
      • ユーザーの話し言葉に近い文章
      • OpenAI と Qdrant
    • インクリメンタル検索をフロントエンドだけで完結する。メインスレッドをブロックしないようWeb Workerを使う
    • 400件のFAQに対し20000件ぐらいの質問文
      • 400KBぐらいしかない
  • 本当に役立つFAQ検索システムを目指して - Nota TechConf
  • 顧客体験向上のキーは「必要な情報に・正しく到達」すること(コールセンター白書より)
  • FAQは重要なユーザータッチポイント
    • 検索性の問題と、コンテンツの問題
  • 検索ヒット率の改善サイクル
    • みるべきKPI ←←大事なポイントだったのに書けなかった!

どこに何の問題があるだろう? HWからSWまでの全領域を横断した最速解決を支援する生成AI活用

佐々木 了 @gzock / 株式会社ビットキー テックリード

  • スマートロックの会社。ただそれだけじゃない
  • ビットキーにおけるAI活用
    • プロダクトへの組み込みと、社内での利用。今回のメインは後者
  • 日々現場で発生するトラブル対応の自己解決支援にAIを活用している
  • 課題:領域を横断するトラブル対応の難しさ
    • toC領域はなんとかなる
    • toB向けはカスタマーサクセス部隊の担当者へ直接つながる
    • →とんでもない脳内辞書を持った職人が生まれる
  • 解決:職人芸のAI化
    • ナレッジのデータベースが作られはじめていた
    • それを材料にSlackボットを作成
    • 結果を👍👎で評価
    • 開発側では、質問と応答と評価を後で見て色々チューニング
    • 最初はVertex AIベース→性能よくないのでAWS Bedrock→Gemini 1.5 Proが最も精度が高い
  • ビットキーはマルチクラウド
  • 生成AIの精度を上げるためにも、そもそものデータをどう集めるか?どうフィードバックして改善するか?が大事
  • それっぽいものは簡単につくれる
    • が、現場での質問は開発側の想定を軽々と超えてくる
    • 巻き込み力が必要不可欠
  • まずはスコープ絞って、それに特化したデータを集めつつ、試行錯誤するのがオススメ
    • 汎用性を持たせようとすると泥沼にハマっていく

パネルディスカッション

メルカリ濱村 甚平さん

メ)メルカリ、ビ)ビットキー、H)Helpfeel

Q1. CSチームとの目線合わせや連携をどうやってますか?

  • メ)CS組織がでかい。普段どんな問い合わせが多いのか、などを取りまとめてくれるプログラムマネージャーがいて、その方が開発側のデイリーに参加している
    • いわゆるスクラムっぽく回している?
    • YES。PdMもいるが、僕らのユーザーは社内にいるので、カウンターパートという存在
  • ビ)しょっちゅうそのへんでCSの人たちと話している。エンジニアの人と話すより多いかも。愚直に人間同士のコミュニケーション
  • H)FAQのプラットフォームを作っており、当社のCSがお客様とのMTGを行っている。そこで具体的な検索クエリを見てる。CSは顧客とかなり仲良くなっている

Q2. 生成AI使ってぶっちゃけどう?上手くいってる?

  • メ)道半ば。正式に採用されてないがテストはしてる。一部問い合わせに使ってみたり
  • H)検索にそこまで深く使うということはしていない。生成AIを検索に使おうとするとRAGになるが、結局裏に検索エンジン使ってるので検索エンジンに注力
    • 無限にスケールできる頭脳ができたとみなしている。周辺領域で使ってる。雑に書いた文章から記事化する、とか(お客様が機能として使ってる)
  • ビ)同意。本当にtoC向けで表に出すのはリスキー。発表内容の事例がうまくいってるのは人間が介在しているから

Q3. ヘルプセンターを主務としている方々の今後のキャリアはどうすべき?

  • ビ)ヘルプセンターに限った話ではなく、変化についていけるかどうかだと思う。エンジニアもそうだが、本当に単純な、領域絞ったことに対してはけっこうな精度で返してくれるが、それで専門職としての仕事が完全に奪われるとは思わない。むしろ武器として使っていける人が強い

ESLintのflat configについてようやく調べた

背景

ESLint v9からflat configがデフォルトとなり、将来のリリースで古いconfigの書き方は廃止される予定なのは把握していた。その後本格的に調べないままになっていたが、そろそろまずいかもなと思って概要だけでも調査したメモ。

先に簡単なまとめ

flat configとは何か

ESLintの新しい設定システム(config system)のこと。

flat config導入の背景

ESLint's new config system, Part 2: Introduction to flat config - ESLint - Pluggable JavaScript Linter

このあたりに書いてそうだったが、あまり詳しくは理解していない。

ESLintも最初にリリースしてから10年が経過し、複雑化したため、よりシンプルで直感的な設計を目指したぽい。

flat configの書き方

参考: Configuration Files

従来は .eslintrc.* という名前の設定ファイルでJSだけでなくYAMLJSONもサポートしていたが、flat configでは eslint.config.js (または ~.mjs, ~.cjs)というようにJSに統一された。
eslint.config.js については、 package.json"type: "module" と書かれていればESM形式、そうでなければCommonJS形式とみなされる。

flat config の中身は、configuration objectと呼ばれるオブジェクトを配列形式で並べたもの。

// eslint.config.mjs (ESM形式)
import customConfig from "eslint-config-custom";

export default [
  customConfig, // configuration object その1
  
  // configuration object その2
  {
    files: ["**/*.js", "**/*.cjs"],
    rules: {
      "semi": "error",
      "no-unused-vars": "error"
    }  
  },
  // configuration object その3    
  {
    files: ["**/*.js"],
    rules: {
      "no-undef": "error",
      "semi": "warn"
    }  
  }
];

各configuration objectはこれらのプロパティで構成される。

  • name
    • configuration objectの名前。Configuration Naming Conventions によれば “optional, but it is recommended to provide a name for each configuration object, especially when you are creating shared configurations.” とのこと
  • files
    • configuration object を適用したいファイルを、globパターンの配列で指定する。省略した場合、他のconfiguration objectによってマッチしたすべてのファイルが対象になる
  • ignores
    • configuration objectの適用対象外にしたいファイルを、globパターンの配列で指定する
  • languageOptions
    • ecmaVersion, sourceType, globals, parser, parserOptionsを設定する
  • linterOptions: 以下、どちらも元からあったプロパティ
    • noInlineConfig:インラインコメントでのルール適用を禁止する(あればエラーになる)
    • reportUnusedDisableDirectives:コメントでenable/disableしたものの、コードの修正によって意味をなさなくなっているものをどう扱うか(error | warn | off)
  • processor
    • 使ったことないので割愛
  • plugins
  • rules
    • ルール。従来通りの記述
  • settings
    • すべてのルールで共有できるkey-value形式の値

注意点として、あるファイルに対して複数のconfiguration objectがマッチした場合、それらはマージされ、配列の前から順番に適用されるような挙動となる。つまりconfiguration object間でプロパティがバッティングしていた場合は後勝ちとなる。

従来のconfigとの違い

参考:https://eslint.org/docs/latest/use/configure/migration-guide

上記記事の Key Differences between Configuration Formats に主な変更点が記載されている。が、それでも量が多い。
ここでは特に気になったものだけ書く。

また、日本語記事ではこちらがわかりやすかった。

ESLint を eslintrc から Flat Config に移行する、ハマりポイントを添えて。 #JavaScript - Qiita

プラグインのインポート方法

eslintrc では外部のプラグインは以下のように文字列で指定していた。

// .eslintrc.js(抜粋)
module.exports = {
  // ...other config
  plugins: ["jsdoc"],
  ...
}

flat configでは使用するプラグインはconfigファイル内で明示的にimportし、key-valueのペアで使用するプラグイン名とプラグインオブジェクトを指定する。

// eslint.config.js

import jsdoc from "eslint-plugin-jsdoc";

export default [
  {
    files: ["**/*.js"],
    plugins: {
      jsdoc: jsdoc,
    },
    rules: {
      "jsdoc/require-description": "error",
      "jsdoc/check-values": "error",
    },
  },
];

これにより、従来はプラグイン名を eslint-plugin- で始めないといけなかったが、その制約がなくなった。

.eslintignore は廃止

同様に eslintrc の ignorePatterns も廃止。configuration object の ignores を使う。

env プロパティは廃止

特定のランタイム向けのグローバル変数globals というnpmパッケージをインストールし、 globals プロパティに指定して使う

before

// before (.eslintrc.js)
module.exports = {
  env: {
    browser: true,
  },
  globals: {
    myCustomGlobal: "readonly",
  },
  parserOptions: {
    ecmaVersion: 2022,
    sourceType: "module"
  }
  // ...other config
}

after

// eslint.config.js
import globals from "globals";

export default [
  {
    languageOptions: {
      ecmaVersion: 2022,
      sourceType: "module",
      globals: {
        ...globals.browser,
        myCustomGlobal: "readonly"
      }
    }
    // ...other config
  }
];

従来のconfigからの移行方法

ESLint Configuration Migrator (@eslint/migrate-config) というCLIが提供されている。

https://eslint.org/docs/latest/use/configure/migration-guide#migrate-your-config-file

npx @eslint/migrate-config .eslintrc.json

実行すると eslint.config.js が生成される(未確認)。

注意点として、公式ドキュメントには

not guaranteed to work immediately without further modification

とあるのでこれだけではうまくいかないケースもあるらしい。
また、 .eslintrc.js に対してはうまく動かないらしい。

手作業での移行は、先ほども記載した
https://eslint.org/docs/latest/use/configure/migration-guide
を読んで差分を理解し、移行するしかない。

flat config未対応のconfig・pluginを使っている場合

参考:Configuration Migration Guide > Using eslintrc Configs in Flat Config

依存している shareable config がまだ flat config に対応していない場合、FlatCompat というユーティリティを使うことで eslintrc フォーマットから flat config フォーマットに変換できる。

FlatCompat@eslint/eslintrc というパッケージのインストールが必要。

このように、FlatCompat インスタンスを作成した後に適宜メソッドを呼び出して flatconfig 未対応の config 名を渡す。

import { FlatCompat } from "@eslint/eslintrc";
import path from "path";
import { fileURLToPath } from "url";

// mimic CommonJS variables -- not needed if using CommonJS
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const compat = new FlatCompat({
    baseDirectory: __dirname
});

export default [

    // mimic ESLintRC-style extends
    ...compat.extends("eslint-config-my-config"),
];

.extends() 以外にもいくつかメソッドがあるみたい。詳しくは

https://github.com/eslint/eslintrc

のREADME参照。

いつまでに移行が必要?

参考:Flat config rollout plans - ESLint - Pluggable JavaScript Linter

すでに、2024年4月にリリースされた ESLint v9.0.0 からはflat configがデフォルトになっており、従来の config は非推奨(deprecated)という扱い。

v9.0.0 以降で従来の config を使用する場合、ESLINT_USE_FLAT_CONFIG という環境変数false に設定する必要がある。

$ ESLINT_USE_FLAT_CONFIG=false npx eslint src

さらに、v10.0.0 では従来の config は完全に削除される。

v10.0.0 のリリースは参考先のブログ記事では2024年末か2025年初頭と書かれている。

flat config のTypeScript型定義

参考:https://eslint.org/docs/latest/use/configure/migration-guide#typescript-types-for-flat-config-files

DefinitelyTyped にある。

$ npm i -D @types/eslint

eslint.config.js

/** @type import("eslint").Linter.FlatConfig[] */
export default [
  ...
]

と書くと補完が効くようになる。

参考リンク

公式ドキュメント

ブログ記事

スクラムフェス大阪2024でCRE(Customer Reliability Engineer)の話をします

タイトルの通り、6/21(金)-22(土)に開催されるスクラムフェス大阪2024にて登壇します。
スクラムフェス自体初参戦です。楽しみ。

大阪と名前がついてますが鳥取トラックで採択いただき、かつ自分は当日神奈川のサテライト会場に行く予定です。
???

なぜスクラムフェスに登壇しようと思ったか

これまで「Customer系エンジニア座談会」という、CREや近しい職種の方向けのコミュニティで何度か登壇の機会をいただいたり、ブログでのアウトプットをしていました。

今年の目標として、これまでとは違ったコミュニティ、特にCREがまだ知られていなさそうな場で登壇する というのを1つの目標としていました。

その中でもRSGTやスクラムフェスは、

  • 自分自身は参加したことはないものの、前職の頃から同僚が多数参加しており馴染みがあったこと
  • スクラムに閉じずプロダクトマネジメントや組織論など多様なテーマを扱っている印象があったので、「もしかしたら無関係なようでCREの話題も受け入れられるのでは?」と思えたこと

という理由があり、思い切ってプロポーザルを出したのでした。

何の話をするのか

プロポーザルにかなり詳しく書いたので、詳細はそちらを見ていただくとして。

自分がどんな経緯でCREになり、何をしてきたのか、そしてなぜCREを面白いと感じているのかを話すつもりです。
これまでやってきたことの総まとめ的な感じです。

プロポーザルわいわい会の存在

プロポーザルを出した後、こちらのイベントに参加して外部の方から率直なフィードバックをいただくというのをやりました。

(実は金沢の方にも出してたのでこのイベントです)

これが初参加の自分にとっては非常にありがたく、自分のことやCREのことを全く知らない方からのフィードバックはとても参考になりました。

特に、

「あなたはCREに熱中している、CREオタクなんでしょう?我々が聞きたいのはそういう◯◯オタクによる熱量のこもったオタトークなんですよ」
「何が好きなのか、なぜ好きになったのか、どれくらい好きなのか」

というコメントは非常にはっとさせられました。

そこまではプロポーザルの文章は簡潔でこぎれいにまとまった感じになってたのですが、このフィードバックを受けて思いの丈をオリャーっと書きました。

大阪で採択いただけたのはこのわいわい会のおかげだと思います。

おわりに

絶賛登壇資料作成中です。少しでも良いオタトークができるようがんばります。
また、初めての参加なので自分の発表以外も楽しみたい。