オリタケイさんのRT企画(約9000RT!!)の抽選をやった話(プログラム付き)
こんにちは、piconのエンジニアの渋谷幸人です!
どうしてやることになったの?
今回、ご縁があって「オリタケイ」さんというとても素敵なイラストを書く方のお手伝いをしました。
内容は、「Twitter上でリツイートしてくれた人の中から数名の選んで、アイコン用のイラストを書くよ!」といったものでした。
【あなたのアイコン描くよ!企画】
— オリタケイ (@Oritakeikou) August 20, 2018
ご要望に応じてこんな感じ(画像参照)のアイコンイラストを4名くらいの方にお描きします〜〜
ご応募の方はこちらのツイートをRTお願いします!
応募期間は22日の23:59までです。
※鍵付きアカウントは探せないので、公開アカウントの方でお願いします! pic.twitter.com/NGRnBM9jLT
想像以上の大反響で、ネット上にあるツールだと100RTまでしか取得できないということで...
絶望の果てにくれていた とのことだったのですが、たまたまお話する機会があってお手伝いすることになりました。
※ 社長からもこちらの案件を快諾していただきました。
どうやってやったの?
TwitterのAPIの制限が厳しくなっているという話は小耳に挟んでおり、もしかしたら難しいかもな...と思っていました。
その旨を伝えた上で、とりあえずチャレンジしてみました。
調べてみたところ、通常のtweetの取得の方法だと、RTを100件程度しか取得できないことがわかりました。
なんとかできないかと、調査を進めるとこちらの記事を発見しました。
[Twitter API] リツイートを100件より多く取得する方法 | プログラミング生放送
やりたいことドンピシャでした。
特定Tweetの詳細を取得するのではなく、文字列でTweetを検索することでページングを可能にして全件取得を目指します。
実際に開発してみる
あとはAPIの変更を実際に確認した上で、使い慣れているRubyを利用して実行しました。
twitterというGemを利用しています。
APIはこちらのドキュメントを参考にしてます。(現在は15分あたり180回のリクエストまでの制限があります。)
以下が実際のコードです。
一度しっかり動けばいいので、強い実装にはなってないです...
client = Twitter::REST::Client.new do |config| config.consumer_key = "取得したものを入れる" config.consumer_secret = "取得したものを入れる" config.access_token = "取得したものを入れる" config.access_token_secret = "取得したものを入れる" end target_tweet_text = "ご要望に応じてこんな感じ(画像参照)のアイコンイラストを4名くらいの方にお描きします〜〜" number_of_selection = 4 screen_names = [] finish_paging = false max_id = nil while !finish_paging sleep 0.1 search_result = client.search(target_tweet_text, result_type: "recent", max_id: max_id) search_result.attrs[:statuses].each do |status| screen_names.append(status[:user][:screen_name]) p status[:user][:screen_name] end if next_results = search_result.attrs[:search_metadata][:next_results] max_id = next_results.match(/\max_id=(\d+)&q/)[1] else finish_paging = true end end p screen_names.sample(number_of_selection)
まとめ
いつもお世話になっている人の役に立ててよかったです。
美味しいお酒でもおごってもらいたいと思います。
piconでは、一緒にプロダクトを作っていく エンジニア(特にiOS, Android)を 募集しています。
少しでも興味ある方は、ぜひ気軽にDMください!
まずは週末コミットやハッカソンのみの参加でも歓迎です。
↓ 連絡はこちら
BATONリリースで得たサイドプロジェクト開発における勘所
先日BATONというサービスをリリースしました。
piconは普段はiOSアプリの開発をメインでやっています。
そのためWeb経験が少ない2人での開発でした。
そんな中で、 なんとか1ヶ月弱でのリリースを実現出来ました。
今回の記事では、BATONのプロジェクトでの学びをKPT形式で共有したいと思います。
BATONは週末ハッカソン発の サイトプロジェクトとして開発 をしていました。
社内で新規事業を考えている、非エンジニアの人も参考になる内容 になってると思うので、ぜひ読んでみてください。
【徹底解説】正しい「KPT」が仕事の成果を生み出す!進め方のコツ、現場の事例を紹介 | SELECK [セレック]
Keep
新技術を導入する際に経験者に手伝ってもらうのがよかった
新技術を軌道にのせる部分を初学者がやると、設計的にもスピード的にも悲惨なことになりがちだと思います。
今回はJavaScriptすら本格的に開発したことない中で、Reactを採用しました。
そのためReactでの開発経験のあるkotaroさんに、週末開発的な感じで立ち上げに入ってもらい、基本的な作法や技術選定などをリードしていってもらいました。
学習効率を最大化するためにも、長期的な開発速度を維持するためにも、経験者の方に立ち上げを手伝ってもらうのは、本当によかった と思っています。
新技術と使い慣れた技術の選定のバランスがよかった
今回の開発では、スピードは保ちつつも、開発力をアップするための学習も出来ました。
Webクライアントでは、Reactという新技術を使いつつ、そのほかの部分(API / インフラなど)では、徹底して既に経験のある技術を採用しました。
学習と開発スピードのトレードオフの中で、どういうバランスをとっていくのか大事な課題だと思うので、今後も向き合っていきたいと思います。
Problem
開発期間の見積もりが甘かった
当初は1週間程度でのリリースを予定していましたが、実際3週間ほどかかりました。
メイン事業へのリソースを投下できなくなってしまう
BATONはあくまでサイドプロジェクトでした。
なので メイン事業への開発リソースが最優先であるべき なので、リリースが想定よりも伸びたときにメイン事業の進捗に影響が出てしまうケースも考えられました。
リリースが伸びた時の対応を考えておくべきでした。
フロントエンジニアとのコラボレーションが改善の余地がありそう
PMでデザイナーのしょせまるに、デザインとフロントエンド(HTML/CSS)開発をしてもらいました。
HTML/CSSを書いてもらって、それをReactに移行するという形をとっていてたのですが、移行コストが無駄にかかっている感じがありました。
バグをリリース前に発見できなかった
リリース直後、Twitter認証が一部端末でうまく行かないバグが発生しました。
Try
新技術を利用した開発の見積もりは少し多めにとる
爆速開発は、バグとかよくあるミスとか、落とし穴に落ちて這いつくばりながら上がってきて、の繰り返しの土台の上で初めて実現するのであって、簡単に新技術で実現出来るわけじゃないことを痛感した。
— 渋谷幸人 | picon inc. (@yukitoto__) 2018年6月8日
このツイートの通り、どの技術にも落とし穴がたくさんあることを実感しました...
そしてその落とし穴に見事にハマっていきました。(この経験が自分を強くすると信じてます...)
今後は、特に 新技術を採用する際はバッファーを多めにとった見積もり をしたいと思います。
リリースが遅れたときは投下するリソースを制限するようにする
今回は、BATON開発中のタイミングでは、メイン事業での開発タスクが多くなかったので実際には問題はありませんでした。
ただ、サイドプロジェクトに追われてメイン事業の進捗が遅れてしまったら元も子もないです。
もし期限が伸びてしまった場合は、週にx日しかサイドプロジェクトの開発に割かない、というような規約を決めておくといいかなと思いました。
もしくは場合によっては、開発を保留にしておいて手が空いたらやる、ぐらいの判断でもいいかもしれません。
周辺領域の知識を身につけた上で開発をする
今回のケースだとフロントエンジニアにReactについて少し学習してもらえれば、直接Reactでフロントを開発できるようになっていたと思います。
そうしていれば移行作業がなくなるだけではなく、CSSをコンポーネントごとに書くこともできました。
以後は領域をまたぐ際の連携が発生する際には、学習コストを掛けてでも全体の開発効率化を図る選択肢を持っておこうと思います。
QAタイムを導入する
今回はしょせまるがサービスのチェックをする片手間で一人QAを担当していました。
それだと頻度の低いバグや分かりづらいバグを発見できない可能性がありますし、実際に認証という致命的なところで一部端末でバグが発生してしまいました。(遭遇された方、本当に申し訳ないです...)
以後は、 リリース前にQAタイム を導入したいと思います。
社員全員のみならず、バイトなどで人数を補填して、一気にバグをハントする時間を取ることでバグを事前に発見したいと思います。
まとめ
今回のBATONプロジェクトはエンジニアの開発力アップという面でも、piconとしての打ち手の選択肢を増やすことが出来たという面でも、いい挑戦だったと思っています。
この学びをメインの事業にも反映しつつ、これからも開発を進めていきます。
piconでは、一緒にプロダクトを作っていく エンジニア(特にiOS, Android)を 全力で募集しています。
少しでも興味ある方は、ぜひ気軽にDMください!
まずは週末コミットやハッカソンのみの参加でも歓迎です。
↓ 連絡はこちら
TalkroomのiOS高速開発を支える開発規約
こんにちは!piconの唯一のエンジニアの渋谷です!
piconでは、現在エンジニア一人の体制で開発を行っています。
事業拡大にむけて開発クオリティ・スピードともに全く足りていないので、 エンジニア(特にiOS, Android)の方を強く募集 してます!
ただそんな体制の中でも、僕が その他の業務で忙殺されていない限り 以下のような比較的ハイペースで開発が実現出来ています。
Talkroom の初期バージョンは約1週間
大型アップデートも1〜2週間程度
今回は、そんなpiconのiOS開発を支える開発規約について紹介したいと思います!
規約をきっちり決めている
前提としてpiconのiOS開発では、規約が比較的きっちり決まっています。
一人でもあえてがっちり決めてます。
規約が決まっていると、「どこにどんな風に書くか」など不要なところで思考をする必要がなくなるので、UIとかであればほぼ無心で開発できるようになりました。
読みやすさもグンと上がるのでとても気に入っています。(3ヶ月後の自分は他人であるのはなんども痛感しました...
ここでいう規約は、改行や記法の規約にとどまらず、レイヤーの分け方、ファイル内での関数の置き方、変数の定義の仕方など、比較的広い意味での規約です。
今回は、汎用性の高そうなUI周りの規約について紹介したいと思います。
※ PCでご覧になることをおすすめします...
UI周りの規約
picon ではストーリーボードを利用していません。ここは賛否両論あると思うので一旦触れずにおきます、、、w
UIViewControllerのクラスには、Viewの見た目とレイアウトに関することを記述します。
Viewだけにとどまらない処理については、ViewModelで処理するようにしています。
UIViewのサブクラスは以下の基準のいずれかを満たす場合にのみにしてます。
処理もしくは構成が複雑である
共通化できるものである
汎用性が高いものである
可読性を損ねるので、自作のUIViewサブクラスが自作のUIViewサブクラスを持たないようにしています。
UIViewControllerクラスのテンプレートは以下です。
import UIKit import RxSwift final class SampleViewController: UIViewController { // MARK: - Views - // 説明メモ:viewはlazyで定義して、プロパティの初期設定はここで行う // 各Viewのプロパティがかたまりとしてひと目で確認できるのが便利 private lazy var sampleView: UIView = { let view = UIView() view.backgroundColor = UIColor.black view.clipsToBounds = true view.layer.cornerRadius = 10 return view }() // MARK: - Properties - private let viewModel: SampleViewModelType private let disposeBag = DisposeBag() // MARK: - Initializer - // 説明メモ:viewModelは外部から注入する init(viewModel: SampleViewModelType) { super.init(nibName: nil, bundle: nil) self.viewModel = viewModel } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK - Life Cycle Events - override func viewDidLoad() { super.viewDidLoad() configure() setViews() setConstraints() } // MARK: - Setup - // 説明メモ:UIViewControllerに関する設定など private func configure() { view.backgroundColor = UIColor.white } // 説明メモ:viewへのaddはこちらで private func setViews() { view.addSubview(sampleView) } // 説明メモ:viewのレイアウトの制約はこちらで private func setConstraints() { sampleView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true } // 説明メモ:viewのイベント処理はこちらで(piconではRxSwiftを利用してます) private func subscribeViews() { let tapGesture = UITapGestureRecognizer() view.addGestureRecognizer(tapGesture) tapGesture.rx.event .subscribe(onNext: { [weak self] () in // 説明メモ: 簡単な処理ではない限り、関数に切り出す self?.createUser() }) .disposed(by: disposeBag) } // 説明メモ: viewModelのイベントはここでsubscribeする private func subscribeViewModel() { } // MARK: - Other - private func createUser() { // Do something. } } // 説明メモ:Protocolに準拠させる場合はextensionを利用して分離させます extension SampleViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // ... } }
ここまで決まっているとどこに何を書くのか迷いなく書けるようになります。
新たな技術を触る時に、ボイラープレート + コード規約が公開されてると便利だなって思ってます。
ぜひ参考にしてみてください!
おまけ
おまけにViewModelのテンプレートも掲載しておきます。こちらはオープンソース化されているkick starterのコードを参考にしています。
参考記事:
Kickstarter-iOSのViewModelの作り方がウマかった
inputとoutputを明示的にわかりやすくなるのでとても気に入ってます。
import RxSwift protocol SampleViewModelInputs { let submitName: PublishSubject<String> { get } } protocol SampleViewModelOutputs { let submitedName: PublishSubject<Void> { get } } protocol SampleViewModelType { var inputs: SampleViewModelInputs { get } var outputs: SampleViewModelOutputs { get } } final class SampleViewModel: SampleViewModelType, SampleViewModelInputs, SampleViewModelOutputs { // MARK: - Properties var inputs: SampleViewModelInputs { return self } var outputs: SampleViewModelOutputs { return self } private let disposeBag = DisposeBag() // MARK: Inputs let submitName = PublishSubject<String>() // MARK: Outputs let submitedName = PublishSubject<Void>() // MARK: - Initializers init() { setBindings() } // MARK: - Binds - private func setBindings() { submitName .subscribe(onNext: { [weak self] (name) in guard let me = self else { return } self?.updateName(name: name) .subscribe(onNext: { [weak self] _ in // 説明メモ:処理 submitedName.on(.next(())) }) .disposed(by: me.disposeBag) }) .disposed(by: disposeBag) } // MARK: - Other - private func updateName(name: String) -> Observable<Void> { // ... } }
---
piconでは、一緒にプロダクトを作っていく エンジニア(特にiOS, Android)を 全力で募集しています。
少しでも興味ある方は、ぜひ気軽にDMください!
まずは週末コミットやハッカソンのみの参加でも歓迎です。
↓ 連絡はこちら
Talkroomを運営する picon inc. のテックブログをはじめました
こんにちは、渋谷幸人です。 この度、元nanapi CTOの和田さんにおすすめしていただいたこともあり、piconでテックブログを始めることにしました。 今回の記事では、初回ということで、テックブログを始めた背景の説明と、piconについて簡単に紹介したいと思います。
piconについて
普段やっていること
piconは、TalkroomやBATONといった主にティーン向けのサービスを作っている会社です。ワクワクするプロダクトを生み出すlab的な組織をめざしていて、企画・デザインも含めたプロダクトの開発力を強みにしています。
Talkroom
BATON baton.wiki
piconはこれまで、代表でデザイナーの山口とエンジニアの僕の2人でプロダクトを作ってきたのですが、この度3人目のメンバーとして新たにデザイナーが増えたこともあり、そろそろ死に…(以下略)
どうしてブログをはじめたの?
はじめた理由は3つあります。
- piconのことを知ってもらって、エンジニアを採用したい
- 思考や学びの整理をする
- まとまった考えを伝えるのにはブログが今も有益だと思うから
piconのことを知ってもらって、エンジニアを採用したい
自分のことを知ってもらって、興味を持ってくれた方といつか一緒に働けたらと思いはじめました。 piconにおいて、今は僕一人でなんとか回っているのですが、いずれは技術レベル・開発工数的に、立ち行かないときが来ると思っています。
今現在も少しでもいいプロダクトをユーザーに届けるために、一緒に働いてくれるエンジニアの方を探しています。
ブログで役に立つようなことを発信しながら、僕たちのことを知ってもらい、興味を持ってもらえると嬉しいなと思っています。
ブログを通じて、考え方や文化を知った上で興味をもってもらえた人との出会いにはとても価値があると思っています。そういう意味でもブログはとても意義のあるものだと思っています。
思考や学びの整理をする
普段の業務で忙殺されていると、なかなか落ち着いて学びを体系化する余裕がないと思います。 ブログというアウトプット先を持つことで、混沌としていた状況を整理し、反省や学びをまとめる機会をもつことは長期的に見てとても意義のあるものなのではないかと思っています。
まとまった考えを伝えるのにはブログが今も有益だと思うから
今の時代であればTwitterも考えを伝えることができるツールだと思うのですが、それでもブログをはじめる価値はあると思っています。 140字の制限の中では思っていることのすべてを伝えられずにミスコミュニケーションが生まれてしまう可能性はありますし、ものごとを体系的に伝えるのには向いていないと思っています。(後者は技術系の発信をする際においては致命的)
さらに記事がアセットとして溜まりやすく、長期的な目線でも採用に効いてくるという点もあります。 そのような点でブログである意義が十分あると判断して、このブログを開始しました。
発信する内容について
主に以下の3つの方向性で発信していきたいと思っています。(MECEではないのですが)
- 技術的な学び
- スタートアップ開発現場のリアル
- 組織づくり的な学び
技術的な学び
僕はどこかの技術に深く精通しているわけではないので、わかりやすさを重視した入門編的な記事とよくある落とし穴を回避する方法あたりを書ければと思っています。
スタートアップ開発現場のリアル
外からだとわかりづらいスタートアップの開発現場を発信できればと思っています。 どういう開発フローをとっているのか、デザイナーとの協業の方法、技術への向き合い方などスタートアップの良さ・辛さを交えつつ、日々どう業務に向き合っているのかを知ってもらえたらと思っています。
piconの大切な思想として、すべてを素直にオープンにするというものがあります。リアルを発信すると、多少不都合な部分もあると思いますが、そういうのも含めてスタートアップです。入ってから後悔するよりもお互いのことをしっかり理解した上で、働きたいと思うので、他のブログよりもよりリアルに近いものを発信できればと思っています。
組織づくり的な学び
上の項目にもかぶってくるのですが、これからエンジニア組織を作っていくにあたって、いろいろ学んだり課題にぶつかって行くと思います。 1人のエンジニアしかいないところから、魅力的なエンジニアを組織を作っていく奮闘日記的な形で、楽しみにながら学びの多い内容にできればと思っています。
まとめ
どのぐらいの頻度で発信できるかわからないのですが、少しでも読んで良かったと思ってもらえるブログを書いていきたいと思います。 よろしくお願いします。