エンジニア転職日記

エンジニア転職に向けての日記です

専門家に意見をもらいました

概要

私の作成しているオリジナルアプリに関して、専門家に意見をいただきました。今回はその反省点とこれからの行動についてアウトプットします。

今回意見を頂いたのは、個人で塾を経営されており、大手の教育系企業とタイアップして子供向けのプログラミング教育を行っているIさんという方です。

制作物

まず、私の作成しているアプリケーションは、プログラミング教育のメンターを探せるサービスです。

今年の4月から小学校のプログラミング教育が必修になりました。幼少期からIT教育を受けさせることはとても良いことだと思いますが、現場では不安の声も大きいようです。

そこで、いつでも相談できるメンターを探せるアプリがあれば安心してIT教育に取り組めるのではないかと考えました。

詳細は、以下の記事に資料を載せてあります。

 

shangang7321.hatenablog.com

 

そして、以下のようなアプリを作成しました。

f:id:shangang7321:20200905091748g:plain

機能としては、

・ユーザー管理

・メンター一覧

・メンター詳細情報

・定額課金(クレジットカード払い)

・DM

・レビュー

となっています。

 

意見

以下が実際に頂いた意見です。要約して書いているので冷たい印象を受けますが、実際はとても物腰の柔らかい方でした。

①本当に需要があるのだろうか

プログラミング教育の必修化に対する不安自体はかなりあります。ただし、実際のカリキュラムはプログラミング、コーディングをするのではなくあくまでプログラミング的思考を身につけるものです。

"プログラミング教育"のイメージが先行してしまって、実態のない不安が蔓延している状況です。実際、中身を知って怖がるほどのものではないなと感じる人も多いです。

また、大手の学習塾でもプログラミング教育のコースを用意しているところが多いです。

果たしてそのような状況下で、個人に教わりたいと考える人はどれくらいいるのでしょうか。

実際、企画段階でも需要の面は気になっていました。プログラミング的思考の教科書を見ると、 あくまで"プログラミング的思考"の教育であり、そこまで難しい内容に感じられなかったからです。

しかし、読めば理解できる = ニーズがないというのもまた違うと思います。小学校の教科書程度の内容ならば、大体の大人は理解できます。しかし、自分で教えるより塾など学校以外の教育サービスを受けさせることが多いと感じます。

であるならば、プログラミング的思考を教えること自体に付加価値を持たせることは難しいけれども、IT教育に対する安心のニーズは強いと思います。これを今あるリソースで解決するサービスを模索することが必要だと感じました。

②本当に質問できるのだろうか

現在学校で使用している教材は教科書の他にもあります。例えば、指示を入力してそのプログラム通りに動くロボットなど。作成したアプリは自宅からオンラインで質問する想定だと思いますが、学校にある教材は持って帰れないので質問しづらいのではないでしょうか。

これは全くの盲点でした。さすがは現場で教鞭をとっていらっしゃる方だと思いました。このような教材を使っているみたいです。

www.artec-kk.co.jp

これには正直、納得せざるを得ませんでした。リサーチ不足だったと反省しています。

これから

まず今回の学びですが、企画の詰めが甘かったことを痛感しました。

プログラミング教育に対する不安(事実)

→相談できる環境があれば安心(解決策)

という点のみ情報収集してロジックを組み立てていました。

・教育の現場ではどのように教えているのか

・実際に何を教えているのか

・カリキュラムが始まったあとの当事者の印象はどうなのか

あたりのリサーチが抜けていました。今後のサービス企画ではより一次情報に近いリサーチを組み込んで仮説を立てていきます。

 

また、今回作成したアプリですが、リリースまでしっかりやってみたいと思います。意外と需要があるかもしれないし、リリースの経験が積みたいと思ったからです。ただアプリを作っただけでなく、リリース、集客、運用のところでPDCAを回し、今後の糧としたいと思います。

 

 

DM機能の実装(メッセージ投稿)

概要

チャットルーム管理に引き続き、オリジナルアプリのDM機能を実装していきます。今回はメッセージ投稿機能です。

 

shangang7321.hatenablog.com

 

完成図

まずは完成図を確認します。

f:id:shangang7321:20200904084419g:plain

左側のチャット相手の名前をクリックすると、その人とのチャットルームに移動します。下のメッセージ入力欄にメッセージを入力して送信を押すとメッセージが投稿されます。画像を投稿することもできます。

画像ではわかりづらいですが、チャットルーム画面に遷移した時、最新のメッセージが表示されるように一番下のメッセージまでスクロールするようにしてあります。

 

実装方法

早速実装していきます。

まずは、モデルを作成します。

% rails g model message

マイグレーションファイルを編集します。

class CreateMessages < ActiveRecord::Migration[6.0]
def change
create_table :messages do |t|
t.text :content
t.references :room, foreign_key: true
t.references :user, foreign_key: true
t.timestamps
end
end
end

マイグレーションします。

% rails db:migrate

 

続いて、アソシエーションを組みます。モデル間の関係はDB設計の記事で解説しています。

 

shangang7321.hatenablog.com

 

# message.rb
class Message < ApplicationRecord
belongs_to :room
belongs_to :user

 

# room.rb
class Room < ApplicationRecord
 
has_many :messages, dependent: :destroy

 

# user.rb
class User < ApplicationRecord
 
has_many :messages

 

ルーティングを設定します。メッセージを投稿する時、どのルームで投稿されたメッセージなのかをパスから判断できるようにしたいので、roomにネストさせて記述します。

# routes.rb
resources :rooms do
resources :messages
end

 

ルーティングを設定したので、チャット画面のサイドバーからルームを選択できるように実装します。

<div class="rooms">
<% current_user.rooms.each do |room| %>
<div class="room">
<div class="room-name">
<% @another_user = (room.users.where.not(id: current_user.id).to_a)[0] %>
<%= link_to @another_user.nickname, room_messages_path(room) %>
</div>
 
</div>
<% end %>
</div>

解説します。

<% current_user.rooms.each do |room| %>

この記述で、ログイン中のユーザーの属しているルームを1つずつ取り出し、変数roomに格納します。

<% @another_user = (room.users.where.not(id: current_user.id).to_a)[0] %>

roomに属するユーザーのうち、自分ではない方のユーザーを@another_userに格納します。

<%= link_to @another_user.nickname, room_messages_path(room) %>

@another_userのユーザー名を表示させ、リンク先を各ルームに設定しています。

これで、サイドバーの編集は完了です。

 

続いて、入力フォームを作成します。

# _main_chat_html.erb
<%= form_with model: [@room, @message], html: {class: "form"},
local: true do |f|%>
<div class="form-input">
<%= f.text_field :content, class: 'form-message',
placeholder: 'メッセージを入力してください' %>
<label class="form-image">
<span class="image-file">画像</span>
<%= f.file_field :image, class: 'hidden' %>
</label>
</div>
<%= f.submit '送信', class: 'form-submit' %>
<% end %>

form_withのモデルの引数に@roomと@messageを渡しているのは、ルーティングをネストさせているためです。○○ルームの××というメッセージという形でサーバー側にリクエストします。

 

この2つのインスタンス変数をコントローラー側で生成します。

# messages_controller.rb
def index
@message = Message.new
@room = Room.find(params[:room_id])
end

 

それでは、送られてきた値をDBに保存できるようにします。

# messages_controller.rb
def create
@room = Room.find(params[:room_id])
@message = @room.messages.new(message_params)
if @message.save
redirect_to room_messages_path(@room)
else
@messages = @room.messages.includes(:user)
render :index
end
end
 
private

def message_params
params.require(:message).permit(:content, :image).merge(user_id: current_user.id)
end

パラメーターからルームIDとメッセージIDを受け取り、インスタンス変数を生成します。メッセージが保存できたらそのままそのルームにリダイレクトします。

保存できなかった場合は、@messagesにルームのメッセージを格納して再度メッセージ一覧を表示します。

includesメソッドを利用することでN+1問題を回避しています。

 

indexアクションでも、一覧表示ができるようにします。

def index
@message = Message.new
@room = Room.find(params[:room_id])
@messages = @room.messages.includes(:user)
end

 

メッセージを表示できるようにします。

# _main_chat.html.erb
<div class="messages">
<%= render partial: 'message', collection: @messages %>
</div>

collectionオプションは、指定したインスタンス変数の中にある要素の数だけ部分テンプレートが繰り返し表示されるオプションです。

 

# _message.html.erb
<div class="message">
<div class="upper-message">
<div class="message-user">
<!-- 投稿したユーザー名情報を出力する -->
<%= message.user.nickname%>
</div>
<div class="message-date">
<!-- 投稿した時刻を出力する -->
<%= l message.created_at%>
</div>
</div>
<div class="lower-message">
<div class="message-content">
<!-- 投稿したメッセージ内容を記述する -->
<%= message.content%>
</div>
<%= image_tag message.image.variant(resize:'500x500'),
class: 'message-image' if message.image.attached? %>
</div>
</div>

ユーザー名、投稿日時、投稿内容、画像が表示されるようにします。

 

l (エル)メソッドは日付を表示するメソッドです。lメソッドを使って日本時間に対応しています。

日本時間を指定する作業を行います。

# config/application.rb
module Original28318
class Application < Rails::Application
config.load_defaults 6.0config.i18n.default_locale = :ja #追加
config.time_zone = 'Tokyo' #追加
config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag }
↑この記述をするとバリデーションでのビュー崩れが防げる
end
end

 

 

# config/locales/ja.yml
ja:
time:
formats:
default: "%Y/%m/%d %H:%M:%S"

これでサーバー再起動をすると日本時間が表示されます。

画像投稿機能に関しては、ActiveStorageを利用しています。

 

shangang7321.hatenablog.com

 

最後に、メッセージの自動スクロール機能の実装です。

ここまでの記述でメッセージは表示されるようになりましたが、メッセージの表示順は上から下に古い順に表示されます。順番はLINEなどのチャットアプリでも下に新しいメッセージが表示されるので問題ないのですが、ルームに遷移した際、一番上が表示されるので、いちいちスクロールして新しいメッセージを見なければなりません。

それを回避するために、遷移と同時に一番下までスクロールする記述をします。

# _main_chat.html.erb
<script type="text/javascript">
const $scrollAuto = $('.messages');
$scrollAuto.animate({scrollTop: ($scrollAuto[0].scrollHeight + 1000)}, 'fast')
</script>

 

メッセージ全体の要素を$scrollAutoに代入し、ロード時にその要素に関してanimate以下の動きを実行するようにしています。

scrollTopは垂直方向のスクロール量を指定できるプロパティです。メッセージ全体の高さ+1000px分スクロールするようにしています。'fast'はスクロールする速さです。

 

これでメッセージ投稿機能の実装が完了しました。

参考

https://narunaru7638.hatenablog.com/entry/2019/04/12/005634

https://qiita.com/masahisa/items/eaacb0c3b82f4a11fc13

プレゼンテーション

概要

先日、オリジナルアプリの発表の予行練習としてプレゼンテーションをしました。

メンターさんからおすすめされていた書籍『スティーブ・ジョブズ 驚異のプレゼン』を参考に組み立てました。書籍の要点まとめと、実際のプレゼンのフィードバックに対する感想をアウトプットします。

www.amazon.co.jp

要点

まずは書籍のアウトプットです。私なりに参考になった点をまとめます。

箇条書きは諸悪の根源

スライドを作る際、ソフトを起動するとテンプレートが出てきます。その多くは箇条書きを前提として作られています。ジョブズのスライドには無駄な文字が一切ありません。印象に残るかどうかという点において、箇条書きは全く役に立ちません。

聴衆を魅了するプレゼンに必要なのは、スライドではなくストーリーです。ストーリーを軸にプレゼンテーションを構成します。ストーリーはアナログで組み立てます。デバイスを起動せず、紙とペンを使い、時には絵を追加しながら自由に想像を膨らませます。デモンストレーションも積極的に取り入れます。デモによる臨場感あふれる体験は、聴衆を引き込む力があるからです。

なぜ気にかける必要があるのか

聴衆は自分にメリットのない話を熱心に聞いてくれるほど暇ではありません。聞き手を儲けさせることができるならば、そう伝えます。作業がしやすくなる、楽しくなるならそう伝えましょう。ジョブズのプレゼンは、メリットを簡潔に、かつ何度も伝えます。聴衆を迷わせることがありません。

プレゼンをする場合多くは、プレゼンすること自体に集中してしまいます。しかし、忘れてはならないことは、プレゼンの対象は自分ではなく聴衆だということです。聴衆はプレゼンを聴きながら、「なぜこのプレゼンを気にかける必要があるのか」と自問しています。そこに明確に答えてあげることです。ジョブズのプレゼンは、技術の話をせずに、その製品によって人々の生活や体験がどのように変わるかを伝えます。どのようにの前に、なぜを説明するのです。

Twitterのようなヘッドラインを作る

どんなに感動的なプレゼンでも、次の日に覚えている内容はせいぜい1フレーズです。その1フレーズが製品の印象を決めます。アップル製品のヘッドラインは非常に印象に残りやすいです。それは、簡潔、具体的、メリットがわかりやすい、の3要素を全て含んでいるからです。

ヘッドラインは聴衆が受ける印象を決めます。むしろ、ヘッドラインを説明するために全体のプレゼンを構成するべきです。ストーリー構成の早い段階でヘッドラインを作り、それに沿って一貫性のあるメッセージを投げかけていくのです。

ヘッドラインは聴衆にとってより良いビジョンを提案するものです。ある投資家はこう言います。

「何をしたいのかを10ワード以下で表現できないのであれば、私は投資しないし興味もない。」

簡単そうに見せる

スティーブ・ジョブズは、プレゼンテーションという舞台の上では完全に演者です。その日のために舞台を細かく作り込みます。動き、デモ、映像、スライド。その全てがガッチリと噛み合うまで何度も調整します。ジョブズはいとも簡単そうに、そして楽しそうに、自信を持ってプレゼンテーションします。その秘訣は、1日に何十時間も、何日も練習に時間を費やすためです。

ジョブズはプレゼンテーションをインフォテイメントと捉えています。インフォメーションのエンターテイメントということです。聴衆は学びと娯楽の両方を求めています。そのためにはまず、自分が楽しむことです。

並のプレゼンターとジョブズの違いは、アクシデントの際に目立ちます。ジョブズはデモが想定どおりいかない時、逆にそれを利用して聴衆を話に引き込みます。計画通りいかなくても、自分がプレゼンを台無しにしない限り失敗ではありません。全体を意識して、小さなことに気をやまないようにすることです。

 

感想

この本を読み終えた時、やる気に満ち溢れていました。次のプレゼンで、メンターさん達をあっと言わせてやろう、そう思っていました。自分の頭の中では、その光景がありありと見えていました。核心をつく問題提起、それを根本から解決するサービス、そして自分の思い描くビジョン。それを伝えることができれば、確実に素晴らしいプレゼンになると思っていました。

しかし、終わってみれば、なんともパッとしない平凡なプレゼンでした。反省点は以下の3つだと思います。

- プレゼン全体の一貫性の甘さ

- 自信を持った話し方

- 練習不足

完全に準備不足でした。

ただ、プレゼン後にメンターさんにかけていただいた言葉に救われました。

「プレゼンが苦手なのではなくて、経験が足りないだけですよ」

肝に銘じて、これからプレゼン力を磨いていきます。

出典

www.amazon.co.jp

DM機能の実装(チャットルーム管理)

概要

DB設計に引き続き、オリジナルアプリのDM機能を実装していきます。

今回はチャットルーム管理機能の実装です。

 

shangang7321.hatenablog.com

 

実装の流れ

以下のGIF画像のように実装します。

f:id:shangang7321:20200827084625g:plain

流れとしては、

①メンタープロフィールの「チャットで相談する」ボタンを押す

②カレントユーザーとメンターの2人が属しているチャットルームを生成

③チャット画面に遷移

④チャット一覧には相手の名前が表示される

の順番で処理が行われています。

 

実装

まずは、roomsモデル、roomsテーブルを作成します。

% rails g model room

 

マイグレーションファイルはこのように設定します。name(ルーム名)は、基本的にチャット相手の名前を表示するのでnullを許可しています。

class CreateRooms < ActiveRecord::Migration[6.0]
def change
create_table :rooms do |t|
t.string :name
t.timestamps
end
end
end

 

マイグレートします。

% rails db:migrate

 

roomsコントローラーを生成します。

% rails g controller rooms

 

アクションを定義します。

 
def index
end
 
def new
@room = Room.new
end

 

ルーティングを設定します。

resources :rooms, only: [:index,:new,:create]

 

usersテーブルとroomsテーブルは多対多の関係なので、中間テーブルを用意する必要があります。

詳細はDB設計の記事で説明しています。

 

shangang7321.hatenablog.com

 

中間テーブルであるroom_userを作成します。

% rails g model room_user

 

マイグレーションファイルを編集します。

class CreateRoomUsers < ActiveRecord::Migration[6.0]
def change
create_table :room_users do |t|
t.references :room, foreign_key: true
t.references :user, foreign_key: true
t.timestamps
end
end
end

 

マイグレートします。

% rails db:migrate

 

アソシエーションを記載します。

user.rb

has_many :room_users
has_many :rooms, through: :room_users

 

room.rb

has_many :room_users
has_many :users, through: :room_users, dependent: :destroy

dependent: :destroyオプションは、親モデルが削除された時に子モデルも削除するというオプションです。これを追加すると、ルームを削除した時に中間テーブルの情報も削除します。

room_userのテーブルに外部キーを設定しているので、このオプションを付けないと外部キーエラーが発生します。

 

room_user.rb

belongs_to :room
belongs_to :user

 

次は、クライアント側からコントローラーへ渡す値を設定します。

今回のアプリでは、メンタープロフィールの詳細画面に、チャットルーム作成のリンクをとなるボタンを配置しています。

コードは以下の通りです。

<div class="chat-wrapper">
<%= link_to(rooms_path(user_ids: [current_user.id, @profile.user.id]),
method: :post) do %>
<div class="chat-btn">
<div class="chat-p">チャットで相談する</div>
<%= image_tag 'chat.png', class: 'chat-logo'%>
</div>
<% end %>
</div>

rooms_pathのmethod: :postを指定することで、roomsコントローラーのcreateアクションにつながります。

user_ids: [current_user.id, @profile.user.id]

ここの部分でuser_idsをキーとして、[自分のid,相手のid]という配列を渡しています。

 

createアクションを作成します。

def create
@room = Room.new(room_params)
@room.save
redirect_to room_messages_path(@room)
end
 
private
def room_params
params.permit(user_ids: [])
end

Roomクラスのインスタンスが生成、保存された時、パラメーターで受け取ったuser_idsが中間テーブルに保存されます。

つまり、user_ids: [1,2]というパラメーターを受け取ったとすると、

roomsテーブルにはid:1のルームのレコードが保存され、room_usersテーブルには、room_id:1、user_id:1のレコードとroom_id:1、user_id:2のレコードが保存されることになります。

user_idsを受け取るためのストロングパラメーターも設定します。

この処理が終わった後、メッセージ一覧画面に遷移しています。(Messageのルーティングは未設定のためこのままではエラーが出ます)

 

次は、チャットルーム一覧画面の表示です。

チャットルーム一覧部分のコードは以下の通りです。

<div class="rooms">
<% current_user.rooms.each do |room| %>
<div class="room">
<div class="room-name">
<% @another_user = (room.users.where.not(id: current_user.id).to_a)[0] %>
<%= link_to @another_user.nickname, room_messages_path(room) %>
</div>
<div class="delete-room">
<%= link_to "×", room_path(room), method: :delete %>
</div>
</div>
<% end %>
</div>

 

<% current_user.rooms.each do |room| %>

この部分でまず、自分の属しているルームを全て取り出してeach文で1つずつ処理します。

 

<% @another_user = (room.users.where.not(id: current_user.id).to_a)[0] %>
<%= link_to @another_user.nickname, room_messages_path(room) %>

ここでチャット相手の名前が表示されるようになっています。

仕組みとしては、@another_userに、そのルームの自分ではない方のユーザー(つまりチャット相手)の情報を代入して、その名前を表示するようにしています。

 

これで、チャットルーム管理の基本的な実装は完了です。

メッセージ送信機能に関しては別の記事で説明します。

サブスクリプションの導入

概要

オリジナルアプリの作成にて、サブスクリプション型の決済を導入したのでアウトプットします。

一回きり決済の導入方法はPAY.JPの記事にまとめてあります。

今回はその続きです。

 

shangang7321.hatenablog.com

 

PAY.JPでのサブスクリプション課金の流れ 

まずはPAY.JPでのサブスクリプションの流れについて簡単に解説します。

PAY.JPとクライアント、サーバーでは以下のように処理が行われます。

 

①クライアント側でJavaScriptを用いてPAY.JPにカード情報をリクエス

②PAY.JPはそれに対しレスポンスを返し、JavaScriptトークンを生成(公開鍵)

JavaScriptからサーバー側へトークンと決済情報をパラメーターとして送信

④サーバー側はトークンと決済情報をもとにPAY.JPと通信し、決済を行う(秘密鍵

 

基本的な流れは、一回きりの決済と同じです。異なる点は、④の決済情報が少し複雑になる点です。

単発決済の場合はChargeオブジェクトを生成して決済するだけでしたが、サブスクリプションの場合は、

トークンをもとに、Customerオブジェクトを生成

②金額、課金周期などの情報をもつPlanオブジェクトを生成

③どの顧客がどのプランを契約しているのか、という情報をもつSubscriptionオブジェクトを生成

という流れになります。

SubscriptionオブジェクトがPAY.JP上でONになっている時(正確には、statusがactive)になっている時に一定の周期でクレジットカードへの請求が行われます。

実装

 

今回実装したコードの全体像です。

# orders_controller.rb
 
def pay_order
Payjp.api_key = ENV["PAYJP_SECRET_KEY"]
customer = Payjp::Customer.create(card: params[:token])
plan = Payjp::Plan.create(
amount: @order.profile.price,
interval: 'month',
currency: 'jpy'
)
subscription = Payjp::Subscription.create(
customer: customer.id,
plan: plan.id
)
end

 

一行ずつ解説します。

 

Payjp.api_key = ENV["PAYJP_SECRET_KEY"]
ここで、環境変数に保存してある秘密鍵を使ってPAY.JPとのやりとりを可能にします。
 
customer = Payjp::Customer.create(card: params[:token])
 JavaScriptを用いて生成したトークンがパラメーターを通して送られてくるので、それを利用して顧客情報を生成します。すると、PAY.JPの顧客情報に顧客が追加されます。

f:id:shangang7321:20200826091113p:plain

 
plan = Payjp::Plan.create(
amount: @order.profile.price,
interval: 'month',
currency: 'jpy'
)

金額、課金周期、通貨の情報を持ったPlanオブジェクトを生成します。すると、このようにプランが生成されます。

f:id:shangang7321:20200826091344p:plain

 

Payjp::Subscription.create(
customer: customer.id,
plan: plan.id
)

最後に、先ほど生成した顧客情報とプラン情報のIDを用いてSubscriptionオブジェクトを生成します。するとこのようにPAY.JP上でサブスクリプション情報が生成されます。

f:id:shangang7321:20200826091653p:plain

詳細情報には、どの顧客がどのプランで登録しているのか、いつ請求なのか、といった情報が記載されています。

f:id:shangang7321:20200826091813p:plain

これで、実装が完了しました。

参考

https://shingo-sasaki-0529.hatenablog.com/entry/how_to_use_payjp_by_ruby

https://pay.jp/docs/api/?ruby#%E5%AE%9A%E6%9C%9F%E8%AA%B2%E9%87%91%E3%82%92%E5%89%8A%E9%99%A4

スプレッドシートで別シートの情報を抽出する

概要

今回はスプレッドシートの使い方です。

私は今、プログラミングスクールに通っており、転職活動中です。私の通っているスクールは、5人1グループで活動しており、1日に数回コミュニケーションも取ります。

転職支援として、スクールの担当の方から数件ずつ企業の募集要項がGmailで送られてきます。これをみんなで共有したら、効率よく仕事探しができるのではないかと考えました。

要件定義

スプレッドシート作成にあたり、必要な機能は以下の通りです。

・メンバーはGmailの内容を貼り付けるだけで良い

Gmailが貼り付けられたシートは冗長になり見づらいので企業名を着色して見やすくする。

・企業名が一覧表示される別シートを作成する。

f:id:shangang7321:20200825090547g:plain

完成図

実装

企業名の背景を着色する

まずは、 Gmailを貼った時に背景が着色されるようにします。

f:id:shangang7321:20200825090931p:plain

①A列を選択し、右クリック

②条件付き書式をクリック

③「セルの書式設定の条件」を、「次を含むテキスト」を選択

④そのすぐ下の入力欄に「【企業名】」と入力

⑤書式設定のスタイルで背景色を選ぶ

このように設定すると、【企業名】を入力されたセルが着色されます。

 

応募可否のプルダウンを作成する

次は、応募可否のプルダウンを作成します。

f:id:shangang7321:20200825091333p:plain

①B列を選んで右クリック

②「データの入力規則」を選択

③セル範囲を「'企業一覧'!B2:B1001」と入力

これは、B1は「応募可否」というタイトルを表示したいので、そこを範囲外にしています。

④条件:「リストを直接指定」に設定

⑤そのすぐ右の欄に「応募する」「,」「応募しない」と入力

⑥セルにプルダウンリストを表示のチェックマークがついていることを確認

f:id:shangang7321:20200825091833p:plain

これでプルダウンリストが表示されます。

企業一覧に企業名が表示されるようにする

次は、企業一覧に企業名が表示されるようにします。

f:id:shangang7321:20200825091333p:plain

完成形のコードは以下です。

 =QUERY(IMPORTRANGE("1X89YVot9wKt5HvgzheipqV-ri_yqCoBbJy1dnyO9dZM","企業詳細!A1:A1000"),"where Col1 like '%企業名%'")

 

このコードを分解すると、2つの関数で構成されています。

IMPORTRANGE関数

IMPORTRANGE関数は、指定したシートからセルの範囲をインポートする関数です。

構文は以下の通りです

IMPORTRANGE("スプレッドシートID","タブ名!セル範囲")

スプレッドシート IDはスプレッドシートのURLに表示されています。https://docs.google.com/spreadsheets/d/スプレッドシートID/edit

つまり、

IMPORTRANGE("1X89YVot9wKt5HvgzheipqV-ri_yqCoBbJy1dnyO9dZM","企業詳細!A1:A1000")

というコードで、このスプレッドシートの、「企業詳細」というシートのA1からA1000までの範囲をインポートしてきています。

QUERY関数

QUERY関数は、データのフィルタリングやソート、グルーピングが行える関数です。

今回は、where句を使ってデータのフィルタリングを行っています。

where句を使った一般的な構文は以下の通りです。

QUERY(セル範囲, where 条件式)

セル範囲のところには、先ほどのIMPORTRANGE関数が入ります。

条件式のところで、その取ってきたデータの中から、企業名を抜き出して表示する設定をします。

likeと%を使うと、「○○を含む」という条件が指定できます。

Col1は一列目という意味です。

つまり、

"where Col1 like '%企業名%'"

というwhere句は、取ってきたデータの、一列目において、「企業名」が含まれるものという意味になります。

これで、実装が完了しました。

参考

https://monoblog.jp/archives/2077

https://monoblog.jp/archives/300

 

仕事のIQを高める

概要

今回は技術とはあまり関係のない内容です。

 

先日、ある記事を見つけました。その内容は、

「学歴・頭のIQ」で、「仕事能力」は判断できない。仕事ができるかどうかは、「仕事のIQ」にかかっている。

https://toyokeizai.net/articles/-/187350

 というものでした。

学歴、IQと聞くとなんとなく頭が良さそう、仕事ができそうなイメージがありました。

私自身、IQテストなどが結構好きで、よくゲーム感覚でやってみたりするのですが、この記事では、IQについて一刀両断。むしろ、「仕事のIQ」なるものを高める必要があるそうです。

この記事は、『最強の働き方』の著者であるムーギー・キムさんのインタビュー記事でした。

「仕事のIQ」を高めて、『最強に働く』ためのヒントとなるフレーズを私なりにピックアップしたので、ここにアウトプットしておきます。

 

フレーズ

自分が選んだ道で、最高水準の仕事をする。
選ばれるエリートではなく、自分らしい天職を選ぶ。

 これが、この本の目的です。そのためにどのように考え、行動するのかがこれ以降示されていきます。

どんな職業でも、一流の仕事とはつまるところ、一流の基本の積み重ね。

 わかりやすい例でいうならば、ディズニーランドにはゴミが1つも落ちていません。一流のサービスを提供する企業に共通するのは、こうした基本の積み重ねであるといいます。

一流のメモは常にピラミッド構造。

仕事のIQが高い人は、メモをとる時、単に書き殴るだけではなく整然とした論理構造でまとめていきます。話している本人ですら良くわかっていない「言いたいこと」を、構造化して本質を把握していきます。

白板の貴公子を目指せ。

白板は、方向性がバラバラになりがちな会議を組み立て、導いていきます。うまく白板が使える人は、白板を「参加者共通の脳」に見立て、会議の生産性を向上させます。

スティーブ・ジョブズがあなたの資料をみたら?

アップルの広告には無駄な説明が一切なく、シンプルに本質を表現しています。仕事のIQが高い人はメールやプレゼンにしても極力短くシンプルにし、全体像と構造が浮き彫りになる資料を作成します。資料は1枚で全て伝わるのがベストです。

また、人に何か伝えるときは、時系列で話すのではなく、話の全体像(ストーリーライン)をまず話し、大枠を合意することが重要です。

感情を揺さぶる、どうしても伝えたいこと。

良いプレゼンターには、心のそこから迸る、どうしても伝えたいことがあります。反対に、ロジックは直感的に抱いている仮説をもっともらしく説明するための道具にすぎないそうです。

また、それの思いを乗せる声も「ええ声」であることが必要です。

いつまで俺は勉強するつもりなんだ?

勉強ばかりしていて、行動に移せない人、こういう人のことを自己啓発ビンボーと読んでいます。勝負すべきところが見えたら、リスクをとって行動に移さなければ結果は出ません。自己啓発自体は良いことです。しかし、常に、いつまで勉強するつもりなのか、を自問自答して勝負所を見極めることが大切です。

上から降ってくる仕事は当然、つまらない。

やりたい仕事というのは、自分から主体的に作っていくものです。上司から指示された仕事を最速で終わらせて自分の仕事をやることに喜びや価値があります。

面白い仕事をやったもの勝ち、であり、自分で面白い仕事を発掘する主体性の有無が仕事の勝敗を分けるのです。

好きな仕事を全部する。

やりたいこと、は1つに絞らない。好きなことを全部やる。5年後どうなっていたいか。それに近づくことを全部やる。会社に求められる範囲ではなく、自分のしたいこと、理想に近づく行動を全てやることで、それに近づくことができるのです。

これだけは絶対に負けたくない分野

一流の仕事をする人には、絶対に負けたくない分野があります。その壮大なビジョンが人を惹きつけ、自分を律し、改善を重ねていけるのです。

 

感想

「勉強のIQ」は 人から言われたことをその通りにやる能力。

「仕事のIQ」は情熱をもって自ら成し遂げていく能力。

このような理解をしました。そう考えると、確かに全く関係ないように感じます。

仕事のIQを高めるようなマインドセットと行動をしていきたいです。

中でも、

スティーブ・ジョブズがあなたの資料をみたら?
上から降ってくる仕事は当然、つまらない。

 この2つには驚きました。資料は細部までカバーしている方が完璧な仕事だと感じるし、上司の指示に従って評価されることで、より面白い仕事が任せられると思っていたからです。

確かに、人々を感動させるようなプレゼンは伝えたいことが1つ明確にあり、くどくどとロジックを固めたりしていません。

https://www.youtube.com/watch?v=gBumdOWWMhY&feature=emb_logo

また、個人の時代と良く言われるように、これからは会社のリソースを利用して自分の目標を成し遂げることが重要だと感じています。であるならば、指示された仕事はすぐに終わらせ、自分の得意で結果を出せる仕事を見つけ、全力投球して実績を作る働き方が最適だと感じました。

これら2つの思考を武器に活躍していきたいです。

出典

https://www.amazon.co.jp/dp/B01J2RCPFY/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

参考 

https://toyokeizai.net/articles/-/187350