tag:crieit.net,2005:https://crieit.net/tags/Laravel/feed 「Laravel」の記事 - Crieit Crieitでタグ「Laravel」に投稿された最近の記事 2022-06-26T14:52:21+09:00 https://crieit.net/tags/Laravel/feed tag:crieit.net,2005:PublicArticle/18231 2022-06-26T14:43:49+09:00 2022-06-26T14:52:21+09:00 https://crieit.net/posts/Subreco-3 サブスクの解約忘れ・無駄遣いを防止するサービス「Subreco」を開発して得た3つの学び <h2 id="筆者について"><a href="#%E7%AD%86%E8%80%85%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">筆者について</a></h2> <p>「多くのユーザーが実際に使って、価値があるものはなんだろう?」と考えながら、個人開発を趣味ではなく「<strong>収益を出す</strong>」ために行なっています。</p> <p>技術だけでなく、デザインやグロースハックも好きで、色々な視点からWebサービスを作り上げていくのが好きです。</p> <p>今回ご紹介する「<strong><a target="_blank" rel="nofollow noopener" href="https://bit.ly/3niPqoN">Subreco</a></strong>」は個人開発を始めて3つ目のサービスとなります。</p> <p><strong><a target="_blank" rel="nofollow noopener" href="https://bit.ly/3niPqoN">Subrecoの公式サイトはこちら</a></strong></p> <h2 id="なぜ、サブスク管理サービス「Subreco」を作ったのか?"><a href="#%E3%81%AA%E3%81%9C%E3%80%81%E3%82%B5%E3%83%96%E3%82%B9%E3%82%AF%E7%AE%A1%E7%90%86%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%80%8CSubreco%E3%80%8D%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B%EF%BC%9F">なぜ、サブスク管理サービス「Subreco」を作ったのか?</a></h2> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326850/ea6daaa9-5fae-ecc7-c8f1-3a99368d62e8.png" alt="スクリーンショット 2022-06-26 12.44.09.png" /><br /> 自分自身、何度もサブスクの「<strong>解約忘れ</strong>」で失敗した経験があったからです。</p> <p>あなたも、サブスクなどで使っていないサービスを解約し忘れて"<strong>無駄な支払いをしてしまった経験</strong>"ありませんか?</p> <p>家計簿アプリ、クレジットカード会社が提供しているアプリは時々見ていたものの、「<strong>あっこのサービス使ってないのに解約し忘れたぁ!(絶望…)</strong>」ということが何回かあったんですね。</p> <p>1回だけならいいのですが。何回も経験したので「さすがにどうにかしたいなぁ」と思って、次はメモアプリとカレンダーアプリを併用して使っていました。</p> <p>これでサブスクと契約更新日を両方管理できる!対策バッチリ!</p> <p><strong>、、、と思いきや、だんだんメモとカレンダーアプリで二重管理するのが面倒くさくなり、結果的に続かなかったんです。。</strong></p> <p>メモアプリやカレンダーアプリだと「<strong>毎回今月は〇〇を使っていたっけ…?</strong>」とわざわざ自分が使っているサービスを"<strong>意識</strong>"して見直さなければなりません。</p> <p>でも、そんなの毎回意識できないし、面倒ですよね?</p> <p>この経験から、使っているサブスクを「<strong>定期的に見直す仕組みを自動化</strong>」しようと生まれたのがSubrecoです。</p> <h2 id="Subrecoの特徴"><a href="#Subreco%E3%81%AE%E7%89%B9%E5%BE%B4">Subrecoの特徴</a></h2> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326850/9498e705-0014-ad3a-e72c-12981a941dc5.png" alt="スクリーンショット 2022-06-23 13.28.50.png" /><br /> Subrecoの使い方はシンプルに3STEPで完結します。</p> <pre><code>①今使っている全てのサブスクを一括管理して把握する ②各サブスクの契約更新日があるたびに自動通知する ③通知があるたびに「利用継続」or 「利用停止」を判断する </code></pre> <p>契約更新日はメールで自動通知するため、わざわざメモを見直したり、毎回カレンダーで契約更新日を設定し直さなくて済むのがポイント。</p> <p>使っているサブスクを登録しておくだけで、自動でSubrecoが契約更新日をお知らせします。</p> <p><strong><a target="_blank" rel="nofollow noopener" href="https://bit.ly/3niPqoN">Subrecoの公式サイトはこちら</a></strong></p> <h2 id="「Subreco」を作って得た学び"><a href="#%E3%80%8CSubreco%E3%80%8D%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E5%BE%97%E3%81%9F%E5%AD%A6%E3%81%B3">「Subreco」を作って得た学び</a></h2> <pre><code>①慣れないことはしない ②コア機能を徹底的に絞る ③自分は使うのかを考える </code></pre> <p>ここからは実際に<a target="_blank" rel="nofollow noopener" href="https://bit.ly/3niPqoN">Subreco</a>を開発して、得た学びを3つ紹介します。</p> <h3 id="①慣れないことはしない"><a href="#%E2%91%A0%E6%85%A3%E3%82%8C%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8%E3%81%AF%E3%81%97%E3%81%AA%E3%81%84">①慣れないことはしない</a></h3> <p>実は、当初SubrecoはNuxt.jsで作っていました。(ちなみにNuxt.jsを使うのが今回が始めて)</p> <p>最初は順調だったものの、徐々にハマるポイントが多く、開発スピードが落ちてきたので、思い切ってLaravel×Vue.jsでリプレイスしました。</p> <p>結果、開発スピードは<strong>3倍</strong>以上にUP。</p> <p>ここから分かったのは、収益目的で個人開発をする場合、<strong>絶対に自分が慣れているフレームワークで開発すべき</strong>だということ。</p> <p>ただでさえ開発以外にもすべきこと(デザイン、マーケetc.)が多いのに、開発に負荷がかかる進め方は合理的でないと痛感しました。</p> <h3 id="②コア機能を徹底的に絞る"><a href="#%E2%91%A1%E3%82%B3%E3%82%A2%E6%A9%9F%E8%83%BD%E3%82%92%E5%BE%B9%E5%BA%95%E7%9A%84%E3%81%AB%E7%B5%9E%E3%82%8B">②コア機能を徹底的に絞る</a></h3> <p>テレビのリモコンを想像してみましょう。</p> <p><code>・電源の入/切ができる</code><br /> <code>・チャンネルで主要な局が切り替えられる</code></p> <p>一番使う機能が多いのは上記だと思います。</p> <p>しかし、実際にテレビのリモコンを見ると他にもボタンがありますよね。<br /> で、実際にほとんどのボタンを使っていないという方も多いのではないでしょうか?</p> <p>そう。<strong>実際にユーザーが求めている機能はシンプル</strong>であることが多いです。</p> <p>これはWebサービスも同じ。</p> <p><a target="_blank" rel="nofollow noopener" href="https://bit.ly/3niPqoN">Subreco</a>の場合、</p> <pre><code>・サブスクの管理が一覧で見れること ・カレンダー形式で契約更新日を確認できること ・契約更新日を自動でメール通知してくれること </code></pre> <p>これさえあれば、<strong>Subrecoが提供したい価値の必要条件は満たせている</strong>と判断して実装していました。</p> <p>実装前に大事なのは、Webサービスの機能として「<strong>必要条件</strong>」と「<strong>十分条件</strong>」を分けて考えること。</p> <p>これは過去の自分に何回も言い聞かせたいです。</p> <h3 id="③自分は使うのかを考える"><a href="#%E2%91%A2%E8%87%AA%E5%88%86%E3%81%AF%E4%BD%BF%E3%81%86%E3%81%AE%E3%81%8B%E3%82%92%E8%80%83%E3%81%88%E3%82%8B">③自分は使うのかを考える</a></h3> <p>個人開発でアイディアを出す際に、</p> <pre><code>①自分起点・・・自分の課題を解決するアイディア ②相手起点・・・自分以外の人が抱えている課題を解決するアイディア </code></pre> <p>の2パターンがあります。</p> <p>今回思ったのが、個人開発をするという前提に立って言えば、圧倒的に<strong>自分起点</strong>で開発するのが良いと思いました。</p> <p>なぜなら、スタート地点で需要が少なくとも「<strong>1つ</strong>」は存在しているから。<br /> 需要が0の場合はそこからスケールさせようがないですが、1であればスケールさせられる可能性は残っています。</p> <p>また、1番のヘビーユーザーは自分になるため、あった方が良い機能や操作する中で潜在的なバグに気付くことができます。<br /> 最悪、誰も使わなくても自分を助けてくれるツールとして機能するので"<strong>一石三鳥</strong>"ですね。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p><img src="https://storage.googleapis.com/zenn-user-upload/62663bd93952-20220626.png" alt="" /></p> <p>収益目的で個人開発をすると考えることは膨大にあります。</p> <p>もしかしたら、あなたも「<strong>個人開発で収益を出したい!</strong>」と、もがいて、あがいている途中かもしれません。</p> <p>僕もあなたと一緒です...!</p> <p>ただ、辛いことや苦しいことがつきものの個人開発ですが、その過程で得られる</p> <p><strong>「うひょ〜!」という小さな成功体験</strong>(考えていた機能が完成した時etc.)<br /> <strong>「よし進んでるな」という実感(Todoリストにチェックを入れる瞬間)</strong></p> <p>これらは<strong>圧倒的な揺るぎない自信、資産</strong>として必ず残っていきます。</p> <p>だからこそ、個人開発を続けている方は諦めないで、一緒に頑張りましょう!</p> <p>僕は引き続き<a target="_blank" rel="nofollow noopener" href="https://bit.ly/3niPqoN">Subreco</a>の改善を続けていきます!ではでは!</p> <p><strong><a target="_blank" rel="nofollow noopener" href="https://bit.ly/3niPqoN">Subreco</a>を実際に利用してみて、ご要望・感想などありましたら、メッセージ頂けると嬉しいです!^^</strong></p> サイゼン tag:crieit.net,2005:PublicArticle/17693 2021-09-30T07:19:35+09:00 2021-09-30T09:25:05+09:00 https://crieit.net/posts/ProductHunt 海外進出を目指して、ProductHuntへ個人開発サービスを投稿するまでにやったこと&やった結果を全面的にシェアする <h1 id="初めて作った個人開発サービスで海外進出しようという無謀な挑戦"><a href="#%E5%88%9D%E3%82%81%E3%81%A6%E4%BD%9C%E3%81%A3%E3%81%9F%E5%80%8B%E4%BA%BA%E9%96%8B%E7%99%BA%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%A7%E6%B5%B7%E5%A4%96%E9%80%B2%E5%87%BA%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%84%E3%81%86%E7%84%A1%E8%AC%80%E3%81%AA%E6%8C%91%E6%88%A6">初めて作った個人開発サービスで海外進出しようという無謀な挑戦</a></h1> <p>以下の記事の通り、9月頭に2goというサービスを作って公開しました。サービスの詳細は以下のURLから見てもらえればと思いますが、いくつかの理由から世界での公開を元から視野に入れていました。<br /> <a href="https://crieit.net/posts/Github-Issues-2go">https://crieit.net/posts/Github-Issues-2go</a></p> <p><a href="https://crieit.now.sh/upload_images/2ccd9128457814ab80f6aa50fae47a4b615488e83f814.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/2ccd9128457814ab80f6aa50fae47a4b615488e83f814.png?mw=700" alt="スクリーンショット 2021-09-26 16.27.05.png" /></a></p> <ol> <li>英語圏のユーザーも含めたほうがサービスの規模感が大きくなる</li> <li>サービス内容が日本だけに留まらない共通の需要があると思った</li> <li>どこかで挑戦しなくてはならないのなら、ここで挑戦しようと思った(無謀)</li> </ol> <p>こういった背景があり、全てのインターフェースは英語で作ってきました。そして、MVPが9月に完成したので、日本でのアナウンスをしました。海外を意識していたので、日本での進め方はあくまでフィードバックを貰えればくらいに思っていましたが、今思えばここからが既に問題なんだなと考えられます。<br /> <a href="https://crieit.now.sh/upload_images/f1969ee50f2c22b287264f3cd5afceb8615488f2e271d.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f1969ee50f2c22b287264f3cd5afceb8615488f2e271d.png?mw=700" alt="スクリーンショット 2021-09-07 3.13.35.png" /></a></p> <p>私の経験をまとめましたので、自分への戒めと今後トライされる方の参考になれば。</p> <h1 id="日本でやったことと、その結果"><a href="#%E6%97%A5%E6%9C%AC%E3%81%A7%E3%82%84%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8%E3%81%A8%E3%80%81%E3%81%9D%E3%81%AE%E7%B5%90%E6%9E%9C">日本でやったことと、その結果</a></h1> <p>日本でリリースしたときにやったことを書いていきます。</p> <h2 id="Twitterでの開発進捗の共有による露出"><a href="#Twitter%E3%81%A7%E3%81%AE%E9%96%8B%E7%99%BA%E9%80%B2%E6%8D%97%E3%81%AE%E5%85%B1%E6%9C%89%E3%81%AB%E3%82%88%E3%82%8B%E9%9C%B2%E5%87%BA">Twitterでの開発進捗の共有による露出</a></h2> <p>私のTwitterアカウントはコチラですが、元々は現在働いている会社のAwarenessを上げるために、自分自身の考えやnoteなどの記事を共有するために使っていたものでした。そのため、インフラやクラウドなどのトピックが中心のため、100強のフォロワーもそういった傾向がありました。ただし、インフラやクラウドもこれからはアプリケーションレイヤーがわかっていないと語れないなと思い、個人開発をすることで開発者の気持ちを理解していこうとしている途中でした。<br /> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/jnakajima1982">https://twitter.com/jnakajima1982</a></p> <h3 id="Twitterでの取り組み内容"><a href="#Twitter%E3%81%A7%E3%81%AE%E5%8F%96%E3%82%8A%E7%B5%84%E3%81%BF%E5%86%85%E5%AE%B9">Twitterでの取り組み内容</a></h3> <p>そのため、絶対数としてこういったアプリレイヤーに興味がある人が少ないということもあり、開発進捗を共有したとしても反応がほぼもらえないという状況が続きました。そこで、私は以下を取り組みました。<br /> 1. 「#個人開発」や「#今日の積み上げ」といったハッシュタグを使った投稿を増やした<br /> 2. 上記ハッシュタグにまつわる個人開発者を中心にフォローを増やした<br /> 3. 自分自身で話題を作るより、フォローしている人のTweetに引用RTするようにした<br />  </p> <h3 id="結果と考察"><a href="#%E7%B5%90%E6%9E%9C%E3%81%A8%E8%80%83%E5%AF%9F">結果と考察</a></h3> <p>「#個人開発」に関しては普段よりはインプレッションが増えましたが、反応が劇的に増えた感じはしませんでした。これには2つの原因があると考えています。「どんなサービスかわかりにくかった(プロフィールもわかりにくかった)」のと、「作っているサービスが英語」だったため、ハードルが高かったのだと思っています。それでも少しずつフォロワーは増え、最終的には今回の取り組みで50フォロワーくらい増えたので、コツコツやっていくことが重要で、指数関数的に上がることになるのではないかなと思っていますので、継続が必要です。</p> <p>ただし、私のアカウントが公共分野(デジタル庁など)のインフラ・クラウドと、個人開発が混ざっているので、アカウントを分けるべきか非常に迷っています。フォロワー0から作り直すリスクと、複数アカウントを運用することの大変さに応えられるのかに解がないため、一旦は1つのアカウントとしています。</p> <p><a href="https://crieit.now.sh/upload_images/89697e0fc27d4936e961e842ff9c0e1861548905416a3.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/89697e0fc27d4936e961e842ff9c0e1861548905416a3.png?mw=700" alt="twitter (1).png" /></a></p> <p>また、 「#今日の積み上げ」は、インプレッションが非常に増え、リアクションも同時に増えるのですが、フォロワーが増えません。これは個人開発に留まらないユーザーが大量に流入しているせいだと思いますが、どちらかと言うとお互いに励まし合おうというハッシュタグの位置づけになっていると思われるので、このような結果になっているのだと思います。自分自身の精神安定の観点で、たまに投稿して安心するくらいが丁度いいと思っています。</p> <p>3については、私自身が有益なことをTweetすることができればいいのですが、いざTwitterの画面を開いてなにか書こうと思ったときに、思いつくことには限界があったんですよね。特に、何がウケるのかみたいなことを考えだしたのもいけなかったんだと思います。なので、フォローしている人は私が興味があってフォローしているわけで、その人が話題にしていることに対して引用RTすることにして、自分の意見を言っていこうと考えました。</p> <p>これは意外と効果があります。Twitter上での表示のされ方も、元Tweetが強ければ同時に表示されることもあります。また、何より引用RTした相手からのコメントを頂ける確率も高く、それがインプレッションの増加に繋がる結果が多かったと思います。</p> <h3 id="反省と今後"><a href="#%E5%8F%8D%E7%9C%81%E3%81%A8%E4%BB%8A%E5%BE%8C">反省と今後</a></h3> <p>いずれにしても、Twitterでの認知度向上は一朝一夕ではいきませんので継続した活動が必要ということが身に沁みました。後ほど触れますが、ProductHuntなどは、このようなフォロワーの数が少ない開発者を掘り出して世に出すためのサービスという大前提があるのですが、現実問題として規模の戦いは存在すると実感しましたので、Twitter等のSNSでコミュニティを形成する必要を感じさせられました。</p> <p>特に英語圏での情報発信を考えると、英語用Twitterアカウントを作ったのですが、日本語用Twitterアカウントだけでも苦労しているのに、英語で書いて運用していくというのはとても大変なことです。そのため、英語用Twitterアカウントはほとんど活動ができていません。</p> <h2 id="運営者ギルドへの参加"><a href="#%E9%81%8B%E5%96%B6%E8%80%85%E3%82%AE%E3%83%AB%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E5%8A%A0">運営者ギルドへの参加</a></h2> <p>Twitterを徘徊していると、運営者ギルドという存在を知りました。まさに私が陥っているような状況が冒頭に書かれていました。<br /> <a target="_blank" rel="nofollow noopener" href="https://qiita.com/organizations/admin-guild">https://qiita.com/organizations/admin-guild</a></p> <blockquote> <p>作ったWebサービス、全然使われない……<br /> どうやってマネタイズしよう<br /> どこまで作り込んでからリリースすればいいんだろう<br /> デザイン難しすぎ<br /> 利用規約はどうすれば?<br /> この先どうやってサービスを伸ばしていけばいいのか……<br /> Slackでの運営形態になっており、中の活動が全く見えなかったので、入れていただくかを非常に悩んだのですが、何事もチャレンジだと思ったので、連絡させて頂き、無事入らせて頂きました。</p> </blockquote> <p><a href="https://crieit.now.sh/upload_images/9a13068ab299538fc8dcc14cfa4026f4615489143c8f5.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/9a13068ab299538fc8dcc14cfa4026f4615489143c8f5.png?mw=700" alt="image (28).png" /></a></p> <h3 id="結果と考察"><a href="#%E7%B5%90%E6%9E%9C%E3%81%A8%E8%80%83%E5%AF%9F">結果と考察</a></h3> <p>結果から言うと、個人開発をしている人は入ったほうが良いです。下手な質問をしたら、ぶっ飛ばされるのではないかとビクビクしていましたが、そんな事は全くありませんでした。唯一あるとするならば、自分自身で発信したことには多くの意見がもらえてモチベーションに繋がりますが、自分自身で発信しない方はここで何をしていいかわからなくなってしまうと思います。</p> <p>私は、実運用ではどのようにしているかなどは、こういった限定されたユーザーだけが参加するコミュニティだからこそ聞ける生の声が本当に貴重だと思いました。また、今回のProductHuntのチャレンジなどを好意的に捉えてくださるだけでなく、普段の自分自身の開発の進捗にコメントいただける方もいらっしゃり、個人開発の課題となりがちなモチベーション維持にもなりました。</p> <p>だからこそ、私自身がコミュニティの一部として、他の方が同様な状況にいる場合には、積極的に自分の経験を還元する必要があると思い、いろいろな方のチャンネルに入るようにしました。</p> <h2 id="技術コミュニティメディアへのサービス開発記事の投稿"><a href="#%E6%8A%80%E8%A1%93%E3%82%B3%E3%83%9F%E3%83%A5%E3%83%8B%E3%83%86%E3%82%A3%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2%E3%81%B8%E3%81%AE%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E9%96%8B%E7%99%BA%E8%A8%98%E4%BA%8B%E3%81%AE%E6%8A%95%E7%A8%BF">技術コミュニティメディアへのサービス開発記事の投稿</a></h2> <p>Twitterや運営者ギルド以外では、とにかくサービスを知ってもらえるチャネルを増やそうとしていました。そこで以下の技術コミュニティメディアに記事を投稿してみました。<br /> - Zenn:https://zenn.dev/nice2have/articles/aa15eccd13a23c<br /> - Qiita:https://qiita.com/nice2have/items/28449ae4ef45fef2c671<br /> - Crieit: https://crieit.net/posts/Github-Issues-2go<br /> - ツクログ:https://creators.eightbit.jp/service/item4309.html</p> <p>以下にそれぞれのメディアの現時点での結果をまとめます(Google Analytics調べ)。Zennは正直きちんと取れているのかわかりません。ツクログは投稿して間もないのと、どこからデータが取れるのかわからずなので、外しています。<br /> <div class="table-responsive"><table> <thead> <tr> <th>メディア</th> <th>記事閲覧数</th> <th>サービス流入数</th> <th>LGTM</th> </tr> </thead> <tbody> <tr> <td>Zenn</td> <td>34</td> <td>10</td> <td>4</td> </tr> <tr> <td>Qiita</td> <td>1468</td> <td>261</td> <td>7</td> </tr> <tr> <td>Crieit</td> <td>1198</td> <td>66</td> <td>1</td> </tr> </tbody> </table></div></p> <h3 id="結果と考察"><a href="#%E7%B5%90%E6%9E%9C%E3%81%A8%E8%80%83%E5%AF%9F">結果と考察</a></h3> <p>いずれにせよ、どのメディアにも投稿することは確実に認知度とサービス流入に繋がっていると言えますので、サービスローンチのタイミングだけでなく、書く内容がある限り、投稿し続けると良いと思います、、、が、やっぱり書くのって大変なんですよね。さらに、メディアによってトレンドがあるから、書く内容を変えたほうがよいというのを見たのですが、全く同じ記事を上げているのが現状です。まずは続けることが大事なので、しばらくはそれを継続しようと思っています。</p> <h3 id="ダイレクトアプローチ"><a href="#%E3%83%80%E3%82%A4%E3%83%AC%E3%82%AF%E3%83%88%E3%82%A2%E3%83%97%E3%83%AD%E3%83%BC%E3%83%81">ダイレクトアプローチ</a></h3> <p><a href="https://crieit.now.sh/upload_images/d3971adefd981bac418520bb891203cb61548925cc9ef.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/d3971adefd981bac418520bb891203cb61548925cc9ef.png?mw=700" alt="lp_issues.png" /></a><br /> 追加でした作業についても記録しておきます。2goというサービスの特性上、Github Issueを利用している/利用見込みのユーザーがターゲットになります。そのため、メディア上にGithub Issueについて記事を書いている人へ直接連絡して実際に利用していただくことで、フィードバックを受けて改善に生かしていこうと思いました。</p> <p>Google検索からたどり着いた5件にコメントをしてコミュニケーションを図ってみたのですが、どこからも未だ返事がない状況です。Twitter上でキーワード検索してアプローチしたこともありましたが、ちょっと利用用途が異なったようで、試してもらうまでに至りませんでした。</p> <p>以上のアプローチで、面白いですとか、良いサービスですねなど言われるものの、今思えば、やはり利用されるだけの魅力やユースケースが見出してもらえなかったのだと思いました。</p> <h2 id="まとめ:日本での取り組み"><a href="#%E3%81%BE%E3%81%A8%E3%82%81%EF%BC%9A%E6%97%A5%E6%9C%AC%E3%81%A7%E3%81%AE%E5%8F%96%E3%82%8A%E7%B5%84%E3%81%BF">まとめ:日本での取り組み</a></h2> <p>海外進出を前提に置いていたため、以下の2点の理由で、Githubアカウントでログインしてまで試してくれた人は、2桁にすら行きませんでした。<br /> - 日本での取り組みを正直本気で取り組んだとは言えない<br /> - 英語のインターフェースのため、伝わりづらかった</p> <p>そこで、Githubアカウントでログインすることのハードルが高いと思い、ログイン不要で誰にでも触れるサンプルを追加開発して提供してみたのですが、こちらも時たま試す人が現れるくらいで、試すことすらしてもらえないのかと打ちひしがれましたorz</p> <p>ほとんどのユーザーアクティビティ(サービス登録/ログイン/公開設定)が発生すると、Slackに通知が飛んでくるようにしていたのですが、たまにしか飛んでこず、こちらも現時点では自分のログイン動作だけが通知される閑古鳥が鳴いている状態です。</p> <h1 id="海外編:Product Hunt"><a href="#%E6%B5%B7%E5%A4%96%E7%B7%A8%EF%BC%9AProduct+Hunt">海外編:Product Hunt</a></h1> <p>つらつらと書いてきましたが、これからが本編です。当時、海外進出しか見えていなかった私は、海外での認知度を上げるための方策を調査していました。調べていくと以下の2つのサービスがマッチすると思いました。</p> <ol> <li>Product Hunt : https://www.producthunt.com/</li> <li>Indie Hackers : https://www.indiehackers.com/</li> </ol> <p>これらのサービスでは、個人開発者やスタートアップが自分の作ったプロダクトを投稿して、認知度を上げることが毎日のように行われています。ただ、Indie Hackersの方は招待制でしか入れず、Redditなどを徘徊してもInvitation Codeを求める人はいるものの、なかなか何もない状態でそれがもらえる人は見られなかったので、一旦Product Huntにフォーカスすることに決めました。</p> <h2 id="Product Huntへの投稿を決心"><a href="#Product+Hunt%E3%81%B8%E3%81%AE%E6%8A%95%E7%A8%BF%E3%82%92%E6%B1%BA%E5%BF%83">Product Huntへの投稿を決心</a></h2> <p>まずは経験者のまとめを読み漁りました。具体的には以下の記事を読みました。この中でも、本当に有効だったこと、今では有効ではないこと、役に立たないことがあるので、それを自分なりに整理していきました。とにかくやれることはやりきらないと、次につながらないと思い計画していきました。</p> <p><a href="https://crieit.net/posts/7">https://crieit.net/posts/7</a><br /> <a target="_blank" rel="nofollow noopener" href="https://jp.taishikato.com/posts/i-want-to-prove-that-japanese-can-compete-in-english-speaking-countries">https://jp.taishikato.com/posts/i-want-to-prove-that-japanese-can-compete-in-english-speaking-countries</a><br /> <a target="_blank" rel="nofollow noopener" href="https://blog.notsobad.jp/entry/2019/12/23/232807">https://blog.notsobad.jp/entry/2019/12/23/232807</a><br /> <a target="_blank" rel="nofollow noopener" href="https://blog.notsobad.jp/entry/bungo-search-product-hunt">https://blog.notsobad.jp/entry/bungo-search-product-hunt</a></p> <h3 id="Product Hunt攻略計画"><a href="#Product+Hunt%E6%94%BB%E7%95%A5%E8%A8%88%E7%94%BB">Product Hunt攻略計画</a></h3> <p>先述の記事を読んで私が立てた当日の計画は以下のとおりです。<br /> 1. 太平洋時間 0:01(日本時間 16:01)からその日のランキングレース開始。<br /> 2. 1時間くらい様子をみて、Google や Facebook からのプロダクトなどのビッグサービスが投稿されていないのを確認してから投稿。<br /> 3. Twitter で Product Hunt への投稿を英語でアナウンス。 @ProductHuntをメンションする。<br /> 4. Product Hunt 上の紹介ページ URL が取得できるので、それを基に Product Hunt Card 作成(Medium の場合は URL を貼り付けるだけで OK)し、Medium 投稿。<br /> 5. ProductHunt の URL を使って Landing Page に反映し、導線を作る。<br /> 6. Medium の記事を、Product Hunt 上のプロダクト紹介ページに関連記事として貼り付け。<br /> 7. Medium の記事を、Hacker News に投稿(Show HN:をタイトルにつけて投稿)<br /> 8. Reddit に投稿<br /> 9. コメントが入ったらそれに返信していく。</p> <p>また、投稿当日までの計画は以下のとおりです。<br /> 1. 投稿用のランディングページを作る<br /> 2. 投稿用の動画(英語)を作る<br /> 3. Medium/HackersNews/Redditの記事を準備する<br /> 4. Product Huntのupcoming Productに登録する<br /> 5. Product Hunt投稿内容の準備をする<br /> 6. 最低限必要な機能の整備(退会機能・規約)<br /> 7. 著名なProduct HuntersにReview Requestをして、認知してもらう</p> <p>簡単に言ってしまうと、以下の2点に集約されます。すごくシンプルです。<br /> - ProductHuntの投稿を魅力的なものにする<br /> - ProductHuntのupvoteを得るための導線をできるだけ多く作る</p> <h4 id="投稿当日までの準備と結果"><a href="#%E6%8A%95%E7%A8%BF%E5%BD%93%E6%97%A5%E3%81%BE%E3%81%A7%E3%81%AE%E6%BA%96%E5%82%99%E3%81%A8%E7%B5%90%E6%9E%9C">投稿当日までの準備と結果</a></h4> <p>順番は前後しますが、投稿当日までの計画について共有します。</p> <h5 id="ランディングページ"><a href="#%E3%83%A9%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%83%9A%E3%83%BC%E3%82%B8">ランディングページ</a></h5> <p>ランディングページはたいして手間もかからなかったのですが、当日投稿しなければ、貼るURLがわからないため、ボタンだけ作ってVueの機能で表示しない状態で準備しておきました。実際のトップページの見えるところにボタンを置いた程度でした。はっきり言ってダサいですね。<br /> <a href="https://crieit.now.sh/upload_images/a66b3274000d3cb3eea1c45bdc3c27aa6154893919d2d.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/a66b3274000d3cb3eea1c45bdc3c27aa6154893919d2d.png?mw=700" alt="image (27).png" /></a></p> <p>改めて投稿後にいろいろ研究してみましたが、以下のような形で誘導するのはとても有効だと感じました。後にわかりますが、こんなレベルの問題ではないことがわかります。<br /> <a href="https://crieit.now.sh/upload_images/55b3b19e99f9362c582a1295c888addd61548947627a7.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/55b3b19e99f9362c582a1295c888addd61548947627a7.png?mw=700" alt="image (26).png" /></a></p> <hr /> <h5 id="投稿用の動画"><a href="#%E6%8A%95%E7%A8%BF%E7%94%A8%E3%81%AE%E5%8B%95%E7%94%BB">投稿用の動画</a></h5> <p>ProductHuntの投稿にYoutube動画を付けると、Product紹介の一番最初に表示され、自動的に再生される仕組みになっています。そのため、インパクトがあると思ったのと、これをやらねばやらなかったときの効果が今後わからなくなると思い、動画制作に手を付け始めました。しかしながら、以下の問題にぶつかります。</p> <ul> <li>動画編集に知見がない</li> <li>動画ナレーションは英語の必要性がある</li> </ul> <p>動画編集に知見がないので、いろいろ調べたところ、ダビンチリゾルブという動画編集ソフトが良さそうで試してみたところ、操作が全くわからず、説明記事をウロウロしていたのですが、わからなすぎて挫折しそうになっていました。ところが、原点に戻って動画のことは動画で、と思ってYoutubeの解説動画を探しました。</p> <p>そして以下の動画を10分で見たら、一気に進み、こんな私でも動画編集ができるようになりました。基本操作と、動画編集に最低限必要そうな動画を紹介しておきます。</p> <p><a target="_blank" rel="nofollow noopener" href="https://youtu.be/duxtN8ixpLo">https://youtu.be/duxtN8ixpLo</a><br /> <a target="_blank" rel="nofollow noopener" href="https://www.youtube.com/watch?v=0J7lqAnP_64&t=194s">https://www.youtube.com/watch?v=0J7lqAnP_64&t=194s</a></p> <p>ただ、計画もなしに動画編集するとうまく行かなったので、Figmaで整理してみました。ただし、これで一旦動画を作ったのですが、文字だらけでなかなか理解しにくいものになってしまいました。<br /> <a href="https://crieit.now.sh/upload_images/7ef5b8ff4b8585d89aea6aae136e0560615488982a3bd.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/7ef5b8ff4b8585d89aea6aae136e0560615488982a3bd.png?mw=700" alt="image (25).png" /></a></p> <p>ここあら紆余曲折があって、ようやく完成した最終版はコチラです。<br /> <a target="_blank" rel="nofollow noopener" href="https://youtu.be/YvcyiAccCBo">https://youtu.be/YvcyiAccCBo</a></p> <p>先にナレーションの英文を考えて、Google Text to Speechに喋らせて、それに合わせて映像を作成するという手順を踏みました。しかしながら、結果的に動画以前の問題であることも発覚します。<br /> <a href="https://crieit.now.sh/upload_images/1854cd2cbe6840ac117d5ae95762703d615488842c9e4.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/1854cd2cbe6840ac117d5ae95762703d615488842c9e4.png?mw=700" alt="image (24).png" /></a></p> <h5 id="Medium/HackersNews/Redditの記事を準備する"><a href="#Medium%2FHackersNews%2FReddit%E3%81%AE%E8%A8%98%E4%BA%8B%E3%82%92%E6%BA%96%E5%82%99%E3%81%99%E3%82%8B">Medium/HackersNews/Redditの記事を準備する</a></h5> <p>ここから導線となる記事の準備についてお話しいたします。</p> <p><strong>Medium</strong><br /> <a target="_blank" rel="nofollow noopener" href="https://medium.com/@nice2have/2go-road-to-my-first-webservice-5b38666a7dd8">https://medium.com/@nice2have/2go-road-to-my-first-webservice-5b38666a7dd8</a><br /> <a href="https://crieit.now.sh/upload_images/c76742bc401d73b46336fe6b13cfa4c161548878085d9.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c76742bc401d73b46336fe6b13cfa4c161548878085d9.png?mw=700" alt="image (23).png" /></a><br /> - 特に制限もないので、自由に書きましたが、タグについては迷いましたね。サービスの特性上、割り当てるべき適切なタグかどれか未だにわかっていません。<br /> - しかしながら現時点でもView数は2です。そのため、こちらもMediumのフォロワーを増やしておくか、単なるプロダクト説明の置き場と割り切るかのどちらかが今後の戦略となりそうです。<br /> <a href="https://crieit.now.sh/upload_images/36006e156388e53b6d55afc31fa83f0a6154883e1dcc6.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/36006e156388e53b6d55afc31fa83f0a6154883e1dcc6.png?mw=700" alt="image (22).png" /></a></p> <hr /> <p><strong>HackersNews</strong><br /> <a href="https://crieit.now.sh/upload_images/1be5ea94b6dfb0a28f3b04305009befe6154880ca815b.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/1be5ea94b6dfb0a28f3b04305009befe6154880ca815b.png?mw=700" alt="image (21).png" /></a><br /> - Show HNを付けるというルールを守って投稿<br /> - 付けるURLはMediumのページか、サービス自体のURLかは迷いましたが、サービスにProductHuntへの誘導を用意していたので、後者を選択しました。<br /> - しかし残念ながら、GoogleAnalytics上は、HackersNewsからの流入は0でしたので、もう少し工夫が必要か、流れるのが早すぎて流入が期待できないかもしれません。</p> <hr /> <p><strong>Reddit</strong><br /> <a target="_blank" rel="nofollow noopener" href="https://www.reddit.com/r/ProductHunters/comments/px15lq/i_created_my_first_web_site_2go_2go_can_generate/">https://www.reddit.com/r/ProductHunters/comments/px15lq/i_created_my_first_web_site_2go_2go_can_generate/</a><br /> <a href="https://crieit.now.sh/upload_images/210f64e0ce8b159071e2738e1bd35776615487f13bade.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/210f64e0ce8b159071e2738e1bd35776615487f13bade.png?mw=700" alt="image (20).png" /></a><br /> - Karmaというポイントがないと記事が投稿できないという話を見たので、事前に記事投稿やコメントで参加してみました。特にGithub Issueの必要性などを投稿したりして、反応を窺うなどもトライしましたが、慣れていないせいもあって反応も薄かったです。<br /> - どのSubredditに投稿するかは検討しました。ProductHunt / Github / webdev / SaaS / startups / indieHackers / indieDevelopers等、色々調査しました。ProductHuntのSubredditが最も適切かと思いましたが、あまり活況がないのが心配でした。ただ、それ以外のところでは厳しい反応も予想されたので、シンプルにProductHuntのSubredditを投稿先と決定しました。<br /> - その他細かいことですが、RedditのProfileなどもきちんと整備しました。<br /> - しかしながら、RedditのSpamFilterに引っかかって削除されてしまったみたいです…</p> <hr /> <h5 id="Product Huntのupcoming Product"><a href="#Product+Hunt%E3%81%AEupcoming+Product">Product Huntのupcoming Product</a></h5> <p>あまり認知されていませんが、以下のようにサービスローンチ前にユーザーとコミュニケーションができるPre-Postサイトを作ることが出来ます。ただここからSubsriberは1人も登録されませんでした。おそらくProductHuntの著名なユーザーが、次期サービスを立ち上げる前にユーザーとコミュニケーションするためのプラットフォームだと感じましたので、私には当分必要ないと思いました。<br /> <a target="_blank" rel="nofollow noopener" href="https://www.producthunt.com/upcoming/2go">https://www.producthunt.com/upcoming/2go</a></p> <hr /> <h6 id="Product Hunt投稿内容の準備をする"><a href="#Product+Hunt%E6%8A%95%E7%A8%BF%E5%86%85%E5%AE%B9%E3%81%AE%E6%BA%96%E5%82%99%E3%82%92%E3%81%99%E3%82%8B">Product Hunt投稿内容の準備をする</a></h6> <p><a href="https://crieit.now.sh/upload_images/76ebfc15ab748145d665f1c4a4986b7e615487ca134e3.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/76ebfc15ab748145d665f1c4a4986b7e615487ca134e3.png?mw=700" alt="image (19).png" /></a><br /> Product Huntの投稿ページは入力したものが記録されるようになっているので、Submitボタンの直前までを入力しておいて事前に準備しておくことが可能です。今回の画像は、動画作成時に作っていたFigmaデータを画像データに変換して利用することとしました。特に動画は視覚的に、画像は落ち着いて読むように文字を入れるようにしました。</p> <p><a href="https://crieit.now.sh/upload_images/7c82e16b607550ccb13639965cdedb976154879728e68.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/7c82e16b607550ccb13639965cdedb976154879728e68.png?mw=700" alt="スクリーンショット 2021-09-26 16.20.56.png" /></a><br /> <a href="https://crieit.now.sh/upload_images/51240628b6d64bac3d7d4b51f2ba477e615487a283dfe.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/51240628b6d64bac3d7d4b51f2ba477e615487a283dfe.png?mw=700" alt="スクリーンショット 2021-09-26 16.03.43.png" /></a><br /> <a href="https://crieit.now.sh/upload_images/4cb7adb70db8bd9afc4ec8e3c63bc1ed615487a8a64c5.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4cb7adb70db8bd9afc4ec8e3c63bc1ed615487a8a64c5.png?mw=700" alt="スクリーンショット 2021-09-26 16.04.35.png" /></a><br /> <a href="https://crieit.now.sh/upload_images/4937eca85eebe0d18e1ce6a5b2637f91615487ae2d3bc.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4937eca85eebe0d18e1ce6a5b2637f91615487ae2d3bc.png?mw=700" alt="スクリーンショット 2021-09-26 16.04.11.png" /></a><br /> ここで用意しにくいのは、投稿ロゴとして利用できるGIFファイルだと思います。動画や画像イメージは比較的簡単に用意できますが、GIFファイルはどんなものにするところから微妙に悩ましい位置づけです。私は今回動画ファイルを作って出力した後、MovファイルからGIFに変換して利用しました。<br /> <a href="https://crieit.now.sh/upload_images/07acf05940475d852b84873e9766827461548726e8258.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/07acf05940475d852b84873e9766827461548726e8258.gif?mw=700" alt="titleGIF.gif" /></a><br /> 目立たせるために、アニメーションというよりは、全体の色が大きく変わることで目につくように意識して作りました。</p> <hr /> <h5 id="著名なProduct HuntersにReview Request"><a href="#%E8%91%97%E5%90%8D%E3%81%AAProduct+Hunters%E3%81%ABReview+Request">著名なProduct HuntersにReview Request</a></h5> <p>先程の記事の中には著名なProductHunterにお願いして、彼らに周知してProductHuntで彼らをフォローしているユーザーに通知されるようにしたほうが良いという記述がありました。一方で、その機能はなくなったのでやる必要ないよというのも見受けられました。ということは、やってみるしかありません。まずは以下のサイトからTop Huntersを探しました。</p> <p><a target="_blank" rel="nofollow noopener" href="https://yvoschaap.com/producthunt/">https://yvoschaap.com/producthunt/</a></p> <p>それぞれがどういった方なのかまで抑えられなかったので、上から順番にTwitterを見て、直接DMを送れる人にていねいな英文を書いて送りました。…が、結果的に1人からも返信は返ってきませんでした。おそらく、こういった依頼が定常的に来るので、そもそもDMを開いていない可能性が高いです。既読にすらなりませんでしたので。</p> <p>では、このアプローチは不要なんでしょうか。その答えは、私のProductHuntの通知ページにありました。以下のようにフォローしているHunterがUpvoteすると、その通知がフォロワーには届きます。つまり、TopHuntersにUpvoteされると知られる確率が高くなるという理解をしています。ただ、彼らからUpvoteされるためにどうしたらよいかは未だにわかりません。Twitterでフォローされるわけもないので、ProductHuntでDiscussionに参加するなどして自分自身の露出が必要なのかもしれません。</p> <p><a href="https://crieit.now.sh/upload_images/93dd81709da263bd35dc9bdcde62bc5b615486ed95e33.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/93dd81709da263bd35dc9bdcde62bc5b615486ed95e33.png?mw=700" alt="tophunters.png" /></a></p> <p>その他に可能性があるとすると、以下は検討してみてもよいかと思いました。開発者のクローズドなコミュニティがあり、そこで繋がりが作れるかもしれません。なぜなら、$2,000/yearの有料会員制だからです。だからこそ、人数が爆発的に多いわけでもないですし、コミュニケーションが活発なのかもしれません。ただし、個人開発者がここに投資するのは、英語とお金が必要なので、ハードルが高いとは思います。</p> <p><a target="_blank" rel="nofollow noopener" href="https://megamaker.co/club/">https://megamaker.co/club/</a></p> <hr /> <h4 id="投稿当日の結果"><a href="#%E6%8A%95%E7%A8%BF%E5%BD%93%E6%97%A5%E3%81%AE%E7%B5%90%E6%9E%9C">投稿当日の結果</a></h4> <p>改めて、投稿当日の計画を振り返る前に、投稿曜日を検討していました。最初は準備ができた翌日に投稿しようかと思っていましたが、ちょうど週末でした。週末がどう影響するかがわからず、Active User数が減少するのではないかと推測して候補から外しました。また、週明けの月曜日も同様の理由で除外し、現地時間火曜日0時に投稿することとしました。</p> <ol> <li>太平洋時間 0:01(日本時間 16:01)からその日のランキングレース開始。</li> <li>1時間くらい様子をみて、Google や Facebook からのプロダクトなどのビッグサービスが投稿されていないのを確認してから投稿。</li> <li>Twitter で Product Hunt への投稿を英語でアナウンス。 @ProductHuntをメンションする。</li> <li>Product Hunt 上の紹介ページ URL が取得できるので、それを基に Product Hunt Card 作成(Medium の場合は URL を貼り付けるだけで OK)し、Medium 投稿。</li> <li>ProductHunt の URL を使って Landing Page に反映し、導線を作る。</li> <li>Medium の記事を、Product Hunt 上のプロダクト紹介ページに関連記事として貼り付け。</li> <li>Medium の記事を、Hacker News に投稿(Show HN:をタイトルにつけて投稿)</li> <li>Reddit に投稿</li> <li>コメントが入ったらそれに返信していく</li> </ol> <p>まず、予約投稿機能があるので、試してみましたが、正常に動作しませんでした。もしかすると私の現地時間の入力時間が間違っているかもしれませんが、念の為日本時間16時にはPCの前にいたほうがいいかもしれません。</p> <hr /> <h5 id="投稿後の動きの感想"><a href="#%E6%8A%95%E7%A8%BF%E5%BE%8C%E3%81%AE%E5%8B%95%E3%81%8D%E3%81%AE%E6%84%9F%E6%83%B3">投稿後の動きの感想</a></h5> <ul> <li>現地時間0時のタイミングでは、少しでもUpvoteを稼いだProductが上位に行きやすいです。そのため、初速を確保する知り合いやコミュニティへの事前声掛けは重要だと思いました(ただし、Upvoteを直接的に促してはいけません)</li> <li>必要初速Upvoteは10くらいだと思います。トップページに表示できるProductにも限りがあり、そこに載れなければ閲覧数も獲得できないです。</li> <li>必ずUpvote順にソートされるわけではありませんでした。コメントなどの他の要素も見ていると思われます。コメントはUpvote同様に初速に影響する可能性があるので、できれば事前に確保しておきたいところです。ただし、日本人のコミュニティにおいて、Upvoteはしてくれても、コメントまでしてくれる人を確保するのは至難の業だと思います。</li> <li>コメントがないと盛り上がりに欠けるのか、追加のコメントが得られにくいと思います。私はただの1つもコメントを最後まで得られませんでした。他のProductは、共同開発者などがコメントし合うことで盛り上がりを演出している印象を受けました。</li> <li>コメントが来たら返信しながら、投稿スレッドを盛り上げる準備をして待っていましたが、杞憂に終わってしまいました。</li> </ul> <hr /> <h5 id="結果と感想"><a href="#%E7%B5%90%E6%9E%9C%E3%81%A8%E6%84%9F%E6%83%B3">結果と感想</a></h5> <p><a href="https://crieit.now.sh/upload_images/74934dd4ad26684204b3a8d132c39ae6615486b229512.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/74934dd4ad26684204b3a8d132c39ae6615486b229512.png?mw=700" alt="スクリーンショット 2021-09-29 17.18.24.png" /></a></p> <p>最終的な結果はUpvote x15となりました。結果をまとめていきます。<br /> - Upvote x15(しかし、運営者ギルドから半数くらいはUpvoteしてくれた方がいたと思います)<br /> - 流入トラフィック x5(ほとんど流入が見込めませんでした)<br /> - 新規登録ユーザー数 x0(残念ながら一人も使ってくれませんでした)<br /> - サンプルを試したユーザー数 x2(流入トラフィックの割に確率が高かった)</p> <p>重要なのは…</p> <ul> <li>とにかく初速Upvoteを増やして、トップページに載らないと何も始まらない</li> <li>流入さえしてくれれば試してもらえる率はそこそこある</li> <li>投稿内容(文章・動画・画像)の良し悪しが影響するのかはわからなかった</li> <li>導線はほとんど影響しなかった(影響するように仕立て上げるには継続的な活動が必要)</li> <li>TopHuntersに認知される方法があれば、Upvoteを得るための近道になるかも。</li> </ul> <h2 id="ProductHuntへの挑戦は惨敗"><a href="#ProductHunt%E3%81%B8%E3%81%AE%E6%8C%91%E6%88%A6%E3%81%AF%E6%83%A8%E6%95%97">ProductHuntへの挑戦は惨敗</a></h2> <p>多くの方にご協力を頂きましたが、残念ながら私の個人開発サービスのProductHunt挑戦は惨敗に終わったと言って良いでしょう。ただし、考えうる限りのことはやり切ったので、次に繋がる敗戦だと考えています。</p> <p>海外進出のサービスの難しさを以下の点で痛感しています。<br /> - 海外でウケるサービスとかユースケースが、真の意味で理解できない可能性<br /> - 海外で求められるデザインやマーケティング・言い回しが適切かどうかわからない<br /> - 海外でのコミュニティ参加は更に負荷がかかるため、労力に見合うかが不安<br /> - 番外編)ユーザーに提供する規約の英文精査が難しい</p> <p>英語で開発すれば、非常に多くのユーザーに対する市場へのアプローチが可能ですが、このような深刻な悩みがついてまわることになります。いくつかの記事にもありましたが、英語圏の感覚を持つ人にヘルプしてもらわないと難しいかもしれません。</p> <h1 id="最後に…"><a href="#%E6%9C%80%E5%BE%8C%E3%81%AB%E2%80%A6">最後に…</a></h1> <p>想像してよりもずっとずっと個人開発は難しいです。プログラミングの世界だけでなく、デザイン・マーケティングまで1人で取り組まなければならず、かつアイデアの捻出とその中からの選定も全部自分の責任です。だからこそ楽しみがあるわけですが、大変さも同時に存在しています。</p> <p>企業よりも個人開発が気楽な分、企業よりもマーケティングや作業分担にお金がかけられません。特に個人開発はサービスが知られることがなければ、提供するユースケースが知られていないから失敗しているのか、知られていても失敗しているのか判断が難しくなります。</p> <p>そこでやはり重要となってくるのが、コミュニティだと思います。自分の作るプロダクトに意見を言ってくれる、試してみてくれる、拡散して届けてくれる人たちとともに歩まねば成功はあり得ません。そしてそれは継続的な努力によってのみ得られるものだと感じました。</p> <p>私にとって今回の開発は本当に作りたいものに対する準備の意味合いも兼ねていますが、コミュニティとともにモチベーションを維持し、成功の模索をしていきたいと思います。</p> <p>ということで、ぜひ気になる方はTwitterのフォローと、2goの利用をしてみて、フィードバックをいただければと思いますので、最後にリンクを貼って終わりにさせていただきます。</p> <p><a target="_blank" rel="nofollow noopener" href="https://twitter.com/jnakajima1982">https://twitter.com/jnakajima1982</a><br /> <a target="_blank" rel="nofollow noopener" href="https://2go.plus/">https://2go.plus/</a></p> <p>ありがとうございました!</p> jnakajima1982 tag:crieit.net,2005:PublicArticle/17641 2021-09-10T06:00:03+09:00 2021-09-10T06:00:03+09:00 https://crieit.net/posts/Github-Issues-2go Github Issuesをキレイに外部公開するサービス「2go」作ってみた <h1 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h1> <p>今回初めて個人開発で作ったサービスを公開します。今までも何回かトライしていたのですが、なかなか公開までに至らないうちに、なにか問題にぶちあたったり、時間がかかりすぎて情熱が冷めてしまったりしていたので、今回はまずはスモールスタートで公開して改善していくことを心がけました。大体今回の公開まで、開発を始めてから1ヶ月程度になります。毎日朝4時半に起きて、子どもたちが起きる7時過ぎまでを開発時間として取り組んできました。<br /> <img src="https://storage.googleapis.com/zenn-user-upload/1463631d38d985beee6c9289.png" alt="" /></p> <h1 id="どんな人向け?"><a href="#%E3%81%A9%E3%82%93%E3%81%AA%E4%BA%BA%E5%90%91%E3%81%91%EF%BC%9F">どんな人向け?</a></h1> <p>自分で作っているサービスの開発ロードマップをユーザーに公開するために、都度ブログを書いたりするのも大変ですよね。もし、自分のサービスのソースコードをGithubで管理していたとして、Github Issuesを見せるとしてもGithubに馴染みのない人にとっては読みにくいですし、外に出すサービスであればあるほど、Githubのレポジトリは非公開になっていると思います。これをなんとかできないかなと思いました。<br /> <img src="https://storage.googleapis.com/zenn-user-upload/4aad80e2913adc2dac582847.png" alt="" /></p> <h1 id="どんなサービス?"><a href="#%E3%81%A9%E3%82%93%E3%81%AA%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%EF%BC%9F">どんなサービス?</a></h1> <p>まずはこちらを見てください。<br /> <a target="_blank" rel="nofollow noopener" href="https://2go.plus/nice2h/2go/roadmap">https://2go.plus/nice2h/2go/roadmap</a><br /> このようにGithubのレポジトリ内のIssueをMilestone区切りにして、Githubに馴染みのない人にも見やすいロードマップサイトを公開するサービスです。もちろん、非公開のレポジトリを公開設定にすることなく、ロードマップだけを外部公開することができます。<br /> <img src="https://storage.googleapis.com/zenn-user-upload/18ca977fd4aa86432338179e.png" alt="" /><br /> Githubアカウントでログインすると、以下の設定画面になります。レポジトリを選択して、どのMilestoneを共有するかをチェックして保存します。すると、自動的にロードマップサイトのURLが生成されるので、こちらにアクセスすれば常に最新のロードマップを見ることができます。このURLをシェアすれば、多くの人にあなたのサービスのロードマップを簡単にキレイに公開できるわけです。<br /> <img src="https://storage.googleapis.com/zenn-user-upload/d3bf728edcb2592f63689133.png" alt="" /><br /> Milestoneを今まで使っていな方は、Milestoneを作成して、Issueを割り当てればロードマップを整理することができます。また、Labelを活用している方もいらっしゃると思いますので、Milestoneの中のLabelでIssueをフィルタすることもできます。これらを駆使することで、Bugは見せずにenhancementだけ表示するなどのことも可能です。<br /> 今後の予定としては、今はMilestone基点で表示しているところを、Labelベースで表示できるようにもしたいと思っています。その他は、まさに上記のURLを参考にしていただければ、いつも最新です。</p> <h1 id="どんな技術を使ってる?"><a href="#%E3%81%A9%E3%82%93%E3%81%AA%E6%8A%80%E8%A1%93%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%8B%3F">どんな技術を使ってる?</a></h1> <p>企業での開発経験はないので、全て自己流です。書籍やWebサイトを中心に勉強して開発しながら学んできました。念の為、利用している技術は以下のとおりです。<br /> - Laravel : APIとBlade(SSRはやってみたことあり)<br /> - Vue3 : フロントエンド(今回初挑戦)<br /> - Tailwindcss : デザイン(Bootstrapからの脱却)<br /> - Docker : これらの開発環境と、本番でもDocker利用(いずれ分割予定)<br /> - Cloud : Conoha VPS(インフラに時間を掛けたくなかった)</p> <h1 id="気になっていること(随時追加予定)"><a href="#%E6%B0%97%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8%EF%BC%88%E9%9A%8F%E6%99%82%E8%BF%BD%E5%8A%A0%E4%BA%88%E5%AE%9A%EF%BC%89">気になっていること(随時追加予定)</a></h1> <ul> <li>開発環境はLaravel sailを使いましたが、本番は自前でdocker-compose.ymlを使いました。このあたりのコンテナの構成をどのようにしているか気になりました(本番でもsail使う?)</li> <li>本番環境にコードをpullしてからnpm run prodしてbuildが終わるまでにラグがあり、この間は使えない機能が出てしまったりするが、このあたりをみなさんはどのように工夫しているか?</li> <li>DBについては、どこまでレコードを暗号化するか。検索機能などとのトレードオフになると思われるが。。</li> </ul> <h1 id="今後は?"><a href="#%E4%BB%8A%E5%BE%8C%E3%81%AF%EF%BC%9F">今後は?</a></h1> <p>現在alphaフェーズですが、alphaとしてもう1段階リリースの予定があります。多くの人に使っていただき、Feedbackをいただきながら改善して、開発経験を増していきたいと思います。また、今回の個人開発は最初から海外も同様の問題を抱えていると思ったので、最初から英語圏も視野に入っており、今の所すべてのUIは英語にしています。以下の英語Twitterアカウントも作成して、情報発信していこうと思っています。</p> <p><a target="_blank" rel="nofollow noopener" href="https://twitter.com/2go_plus">https://twitter.com/2go_plus</a></p> <p>もちろん、日本語のTwitterは私の今まで通りのアカウントを利用していく予定です。<br /> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/jnakajima1982">https://twitter.com/jnakajima1982</a><br /> ぜひご感想・ご指摘をいただければと思います。</p> jnakajima1982 tag:crieit.net,2005:PublicArticle/17480 2021-07-04T01:29:21+09:00 2022-02-20T18:50:34+09:00 https://crieit.net/posts/php-artisan 【自分用メモ】php artisanコマンド一覧 <h1 id="1. コントローラ(Controller)関連"><a href="#1.+%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%28Controller%29%E9%96%A2%E9%80%A3">1. コントローラ(Controller)関連</a></h1> <h2 id="1-1. コントローラの作成"><a href="#1-1.+%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%81%AE%E4%BD%9C%E6%88%90">1-1. コントローラの作成</a></h2> <pre><code>php artisan make:controller [Controller名] </code></pre> <ul> <li>[Controller名]には拡張子は不要。</li> <li>[Controller名]の命名は「○○Controller」とするのが一般的。</li> </ul> <h2 id="1-2. RESTコントローラの作成"><a href="#1-2.+REST%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%81%AE%E4%BD%9C%E6%88%90">1-2. RESTコントローラの作成</a></h2> <pre><code>php artisan make:controller [RESTコントローラ名] --resource </code></pre> <ul> <li>オプション「--resource」を付けることで、作成されるコントローラにCURD関係のメソッドを自動的に追加してくれる。</li> </ul> <h1 id="2. ビュー(View)関連"><a href="#2.+%E3%83%93%E3%83%A5%E3%83%BC%28View%29%E9%96%A2%E9%80%A3">2. ビュー(View)関連</a></h1> <h2 id="2-1. サービスプロバイダの作成"><a href="#2-1.+%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%83%97%E3%83%AD%E3%83%90%E3%82%A4%E3%83%80%E3%81%AE%E4%BD%9C%E6%88%90">2-1. サービスプロバイダの作成</a></h2> <pre><code>php artisan make:provider [Provider名] </code></pre> <ul> <li>[Provider名]の命名は「○○Provider」とするのが一般的。</li> </ul> <h2 id="2-2. ペジネーションのテンプレートファイルの作成"><a href="#2-2.+%E3%83%9A%E3%82%B8%E3%83%8D%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90">2-2. ペジネーションのテンプレートファイルの作成</a></h2> <pre><code>php artisan vendor:publish --tag=laravel-pagination </code></pre> <ul> <li>ペジネーション:大量データを一定件数ずつ表示するための仕組み。</li> </ul> <h1 id="3. モデル(database)関連"><a href="#3.+%E3%83%A2%E3%83%87%E3%83%AB%28database%29%E9%96%A2%E9%80%A3">3. モデル(database)関連</a></h1> <h2 id="3-1. マイグレーションファイルの作成"><a href="#3-1.+%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90">3-1. マイグレーションファイルの作成</a></h2> <pre><code>php artisan make:migration [マイグレーションファイル名] </code></pre> <ul> <li>[マイグレーションファイル名]の命名は「create_[テーブル名]_table」とするのが一般的。</li> </ul> <pre><code>php artisan session:table </code></pre> <ul> <li>セッション管理用テーブルのマイグレーションファイルを作成する。</li> </ul> <h2 id="3-2. マイグレーション実行"><a href="#3-2.+%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E5%AE%9F%E8%A1%8C">3-2. マイグレーション実行</a></h2> <pre><code>php artisan migrate php artisan migrate:refresh php artisan migrate:refresh -–seed php artisan migrate:reset </code></pre> <ul> <li>「migrate:refresh」とすることで、テーブルの再作成を行うことが出来る。</li> <li>「migrate:refresh」にオプション「-–seed」を追加すると、テーブル再作成後にシーディングを実行してくれる。</li> <li>「migrate:reset」とすることで、全ての作成済みテーブルを削除することが出来る。</li> </ul> <h2 id="3-3. シーダーファイルの作成"><a href="#3-3.+%E3%82%B7%E3%83%BC%E3%83%80%E3%83%BC%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90">3-3. シーダーファイルの作成</a></h2> <pre><code>php artisan make:seeder [シーダーファイル名] </code></pre> <ul> <li>[シーダーファイル名]の命名は「[テーブル名]TableSeeder」とするのが一般的。</li> </ul> <h2 id="3-4. シーディングの実行"><a href="#3-4.+%E3%82%B7%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%AE%E5%AE%9F%E8%A1%8C">3-4. シーディングの実行</a></h2> <pre><code>php artisan db:seed php artisan db:seed --class=[シーダーファイル名] </code></pre> <ul> <li>「-class」オプションを指定すると、シーディングファイルを指定して実行できる。</li> </ul> <h2 id="3-5. モデルの作成"><a href="#3-5.+%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90">3-5. モデルの作成</a></h2> <pre><code>php artisan make:model [モデル名] </code></pre> <ul> <li>[モデル名]はテーブルの単数形とするのが一般的。<br /> 例)テーブル:people → モデル:Person(先頭大文字)</li> </ul> <h1 id="4. Request,Response関連"><a href="#4.+Request%2CResponse%E9%96%A2%E9%80%A3">4. Request,Response関連</a></h1> <h2 id="4-1. ミドルウェアの作成"><a href="#4-1.+%E3%83%9F%E3%83%89%E3%83%AB%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E4%BD%9C%E6%88%90">4-1. ミドルウェアの作成</a></h2> <pre><code>php artisan make:middleware [Middleware名] </code></pre> <ul> <li>[Middleware名]の命名は「○○Middleware」とするのが一般的。</li> </ul> <h2 id="4-2. フォームリクエストの作成"><a href="#4-2.+%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90">4-2. フォームリクエストの作成</a></h2> <pre><code>php artisan make:request [Request名] </code></pre> <ul> <li>[Request名]の命名は「○○Request」とするのが一般的。</li> </ul> <h2 id="4-3. バリデーションルールの作成"><a href="#4-3.+%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90">4-3. バリデーションルールの作成</a></h2> <pre><code>php artisan make:rule [Rule名] </code></pre> <p>・命名規則は特になし。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <p>PHPフレームワーク Laravel入門 第2版<br /> <a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/dp/4798060992/ref=cm_sw_r_tw_dp_47YACT8WRZY9QG47TJ68">https://www.amazon.co.jp/dp/4798060992/ref=cm_sw_r_tw_dp_47YACT8WRZY9QG47TJ68</a><br /> Laravel マイグレーション(migration)の基本<br /> <a target="_blank" rel="nofollow noopener" href="https://noumenon-th.net/programming/2020/01/17/laravel-migration/">https://noumenon-th.net/programming/2020/01/17/laravel-migration/</a><br /> LaravelのSeeding機能を利用してダミーデータを一括挿入<br /> <a target="_blank" rel="nofollow noopener" href="https://reffect.co.jp/laravel/larave-seeding-store-data-in-database#Seed">https://reffect.co.jp/laravel/larave-seeding-store-data-in-database#Seed</a><br /> Laravel 8.x データベース:シーディング<br /> <a target="_blank" rel="nofollow noopener" href="https://readouble.com/laravel/8.x/ja/seeding.html">https://readouble.com/laravel/8.x/ja/seeding.html</a></p> acmz tag:crieit.net,2005:PublicArticle/17227 2021-05-21T16:23:01+09:00 2021-05-21T16:23:01+09:00 https://crieit.net/posts/php-Laravel-60a75fd51f5f0 php(Laravel)でエクセルのインポート機能付けるときに試したもの <h1 id="渡されたデータがエクセルだった"><a href="#%E6%B8%A1%E3%81%95%E3%82%8C%E3%81%9F%E3%83%87%E3%83%BC%E3%82%BF%E3%81%8C%E3%82%A8%E3%82%AF%E3%82%BB%E3%83%AB%E3%81%A0%E3%81%A3%E3%81%9F">渡されたデータがエクセルだった</a></h1> <p>「ほいっじゃあこれ取り込んでね」<br /> と渡されたのは、2~3万行のデータ(エクセル形式)だった。<br /> …えー!CSVじゃないんですかー!?!?CSVはやったことあるけど、エクセルは知らーん!!</p> <p>ということで、3つほどライブラリを試してようやく機能実装が出来たので、その時のメモです</p> <h1 id="Laravel Excel"><a href="#Laravel+Excel">Laravel Excel</a></h1> <p>URL:<a target="_blank" rel="nofollow noopener" href="https://laravel-excel.com">https://laravel-excel.com</a></p> <p>これはLaravelのライブラリ(パッケージ?)ですね。<br /> 後に紹介するPhpSpreadsheetを基に作られております。<br /> エクセルだけでなくcsvも扱えます。</p> <p>使い方も特別難しいわけでもなく、<br /> 公式ドキュメントを落ち着いて読んでいけば大抵は問題ないはずです。</p> <p>…がしかぁし!</p> <p>データ数が少なめのテストデータでは問題ありませんでしたが、<br /> いざ実際の2~3万件データで試したところメモリ不足で死に至りました。(チーン)</p> <p>php-fpmの設定弄ってみたり、<br /> toArrayがいけないのか?と思いonRowで1行ずつinsertしてみたり…。<br /> かなり色々試行錯誤してみましたが解決には至らず、ライブラリ使用自体を断念しました…。</p> <p>(もし解決法ご存知の方がいらっしゃいましたら、そっとご教示いただければ幸いに存じます)</p> <h1 id="PhpSpreadsheet"><a href="#PhpSpreadsheet">PhpSpreadsheet</a></h1> <p>URL:<a target="_blank" rel="nofollow noopener" href="https://phpspreadsheet.readthedocs.io/en/latest/">https://phpspreadsheet.readthedocs.io/en/latest/</a></p> <p>くそう、ならば元であるコイツで試してみるか!<br /> てな感じで、半ヤケクソでやってみました。<br /> なお、phpExcelというライブラリの後継版らしいです。</p> <p>結論、メモリ不足も解決せず、なんなら処理時間も増えて、解決には至りませんでした…。<br /> 使用感としては、シンプルで使いやすいなーとは思いました。<br /> また、laravel excelより使用率が高いので、参考にできる記事も多い(日本語記事も多い)という点は良かったです。</p> <h1 id="Spout"><a href="#Spout">Spout</a></h1> <p>URL:<a target="_blank" rel="nofollow noopener" href="https://opensource.box.com/spout/"> https://opensource.box.com/spout/</a></p> <h4><strong>救 世 主</strong></h4> <p>メモリ不足問題はこれで解決しました!!!<br /> 代わりにCPU使用率がギュイーンと上がりますが。</p> <p>ただこれ、マイナーなのかわかりませんがググってもほぼ出てきません。<br /> 出てきたとしても全部英語です。google翻訳がある世界に生まれてよかった。</p> <p>基本公式ドキュメントを頼りにやるしか無いので、赤ちゃんエンジニアにはちょっと厳しかったです…。<br /> やりたいことが至ってシンプルだったのでなんとかなりましたが。</p> <p>気力があれば、使い方のメモも別で書こうかと思います。来世までにはきっと。</p> <h1 id="なお後日"><a href="#%E3%81%AA%E3%81%8A%E5%BE%8C%E6%97%A5">なお後日</a></h1> <p>えらいひと「ちょっとフォーマット変えたので、再度送るで!これで取り込んでくれや! つCSVファイル」<br /> ワイ「いやCSVで出力できんのかい!!!!!!!!!!!」</p> <p>~完~</p> みみみみみ tag:crieit.net,2005:PublicArticle/16839 2021-04-11T22:13:59+09:00 2021-04-11T22:33:36+09:00 https://crieit.net/posts/PHP-Laravel 【Laravel】ルーティング(URLと実行する処理の関連付け) <h1 id="ルーティング"><a href="#%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0">ルーティング</a></h1> <ol> <li>URLと実行する処理を関連付けする仕組み。</li> <li>Webページの場合、「routes\web.php」に関連付けする情報(ルート情報)を記述する。</li> </ol> <hr /> <h1 id="ルート情報の記載方法"><a href="#%E3%83%AB%E3%83%BC%E3%83%88%E6%83%85%E5%A0%B1%E3%81%AE%E8%A8%98%E8%BC%89%E6%96%B9%E6%B3%95">ルート情報の記載方法</a></h1> <pre><code>1. Route::get(アドレス, 実行する処理); 2. Route::get(アドレス/{パラメータ}, 実行する処理($引数名)); 3. Route::get(アドレス/{パラメータ?}, 実行する処理($引数名=デフォルト値)); 4. Route::get(アドレス/{パラメータ1}/{パラメータ2}, 実行する処理($引数名1, $引数名2)); </code></pre> <ol> <li>[アドレス]:Webブラウザ等で指定されるアドレス</li> <li>[実行する処理]:関数、HTMLドキュメント、テンプレートファイル等</li> <li>[アドレス]を指定されたら、[実行する処理]を呼び出して結果を返却する。</li> <li>{パラメータ}:[アドレス]で{ }に囲まれた部分は、パラメータとして受け取ることが出来る。</li> <li>{パラメータ?}:[アドレス]で{ ?}に囲まれた部分は、任意パラメータとなる。<br />  任意なので、パラメータが渡されないこともある。<br />  パラメータが渡されなかった場合は、実行する処理の「$引数名=デフォルト値」の値が適用される。</li> <li>[/(スラッシュ)]で区切ることで、パラメータを複数渡すことも可能。</li> </ol> <pre><code>例) 1. Route::get( hoge , function () { $html='<html> …'; return $html; } ); 2. Route::get( hoge/{fuga} , function ($fugaValue) { $html='<html> … $fugaValue …'; return $html; } ); 3. Route::get( hoge/{fuga?} , function ($fugaValue='パラメータなし') { $html='<html> … $param …'; return $html; } ); 4. Route::get( hoge/{fuga}/{piyo} , function ($fugaValue, $piyoValue) { $html='<html> … $fugaValue … $piyoValue …'; return $html; } ); </code></pre> <hr /> <h1 id="【参考】"><a href="#%E3%80%90%E5%8F%82%E8%80%83%E3%80%91">【参考】</a></h1> <p>PHPフレームワーク Laravel入門 第2版(<a target="_blank" rel="nofollow noopener" href="https://www.shuwasystem.co.jp/book/9784798060996.html">https://www.shuwasystem.co.jp/book/9784798060996.html</a>)</p> acmz tag:crieit.net,2005:PublicArticle/16813 2021-04-04T00:06:11+09:00 2021-04-11T22:18:08+09:00 https://crieit.net/posts/Laravel-60688463e5095 【Laravel】新規プロジェクト作成~サンプルページ表示 <h1 id="Laravelの新規プロジェクト作成"><a href="#Laravel%E3%81%AE%E6%96%B0%E8%A6%8F%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E4%BD%9C%E6%88%90">Laravelの新規プロジェクト作成</a></h1> <ol> <li>ターミナル(cmd, powershell等)を起動する。</li> <li>プロジェクトを作成したいフォルダまで移動する。</li> <li>下記のどちらかのコマンドを実行する。</li> </ol> <pre><code> laravel new [プロジェクト名] </code></pre> <pre><code> composer create-project laravel/laravel [プロジェクト名] --prefer-dist </code></pre> <hr /> <h1 id="Webサーバ起動"><a href="#Web%E3%82%B5%E3%83%BC%E3%83%90%E8%B5%B7%E5%8B%95">Webサーバ起動</a></h1> <ol> <li>ターミナルで、作成したプロジェクトのフォルダまで移動する。</li> <li>下記コマンドを実行し、Webサーバを起動する。</li> </ol> <pre><code> php artisan serve </code></pre> <ol start="3"> <li>Webブラウザで下記アドレスにアクセスする。<br /> http://localhost:8000/</li> </ol> <hr /> <h1 id="【参考】"><a href="#%E3%80%90%E5%8F%82%E8%80%83%E3%80%91">【参考】</a></h1> <p>PHPフレームワーク Laravel入門 第2版(<a target="_blank" rel="nofollow noopener" href="https://www.shuwasystem.co.jp/book/9784798060996.html">https://www.shuwasystem.co.jp/book/9784798060996.html</a>)</p> acmz tag:crieit.net,2005:PublicArticle/16786 2021-03-28T18:20:44+09:00 2021-08-08T16:13:11+09:00 https://crieit.net/posts/VSCode-Web 【VSCode】拡張機能一覧(主にWeb系システム開発用) <p>個人用メモ。<br /> 主にPHPを使用して開発する環境で使用している拡張機能一覧。<br /> (他のも混じっているけど)<br /> (後で追加・変更・削除するかも)</p> <h1 id="VSCode"><a href="#VSCode">VSCode</a></h1> <ul> <li><p>Bookmarks<br />  あらかじめソースコード中にブックマークを設定しておくと、他の場所からブックマークまで一瞬で移動することが出来る。</p></li> <li><p>indent-rainbow<br />  インデントを色付きで表示してくれる。</p></li> <li><p>Japanese Language Pack for Visual Studio Code<br />  VSCodeの日本語化。</p></li> </ul> <h1 id="HTML"><a href="#HTML">HTML</a></h1> <ul> <li><p>Auto Close Tag<br />  自動的に閉じタグを追記してくれる。</p></li> <li><p>Auto Rename Tag<br />  タグを変更すると、対応する閉じタグを自動的に変更してくれる。</p></li> <li><p>HTML Snippets<br />  HTMLの予測変換を表示してくれる。</p></li> <li><p>HTMLHint<br />  HTMLの文法チェックをしてくれる。</p></li> </ul> <h1 id="PHP(Laravel)"><a href="#PHP%28Laravel%29">PHP(Laravel)</a></h1> <ul> <li><p>Bracket Pair Colorizer 2<br />  メソッドやArrayなどで、対となるカッコを色付きで表示してくれる。</p></li> <li><p>php cs fixer<br />  PHPソースを自動整形してくれる。<br />  ※別途、「php-cf-fixer.phar」のインストールが必要。</p></li> <li><p>PHP Debug<br />  PHPをステップ実行してデバッグできるようになる。</p></li> <li><p>PHP IntelliSense<br />  PHPの予測変換を表示してくれる。</p></li> </ul> <p>【2021.8.8 追加】<br /> * Laravel Blade Snippets<br />  Laravelのbladeファイル内のタグやディレクティブを色付きで表示してくれる。</p> <ul> <li>Laravel Blade formatter<br />  Laravelのbladeファイル用のフォーマッタ。<br />  blade独自のディレクティブもインデントしてくれる(これ重要)。</li> </ul> <h1 id="JavaScript(Node.js,Vue.js)"><a href="#JavaScript%28Node.js%2CVue.js%29">JavaScript(Node.js,Vue.js)</a></h1> <ul> <li><p>ESLint<br />  JavaScriptの構文チェックをリアルタイムで実行してくれる。<br />  ※Vue.jsで使用するには設定が必要。</p></li> <li><p>JavaScript (ES6) code snippets<br />  JavaScriptの予測変換を表示してくれる。</p></li> <li><p>Vetur<br />  Vue.jsコードのシンタックスハイライトやコード補完、リント、フォーマットを行ってくれる。</p></li> </ul> <h1 id="CSS(Sass,SCSS)"><a href="#CSS%28Sass%2CSCSS%29">CSS(Sass,SCSS)</a></h1> <ul> <li><p>IntelliSense for CSS class names in HTML<br />  CSSクラス名を入力するときに、入力補完してくれる。</p></li> <li><p>SCSS Formatter<br />  SCSSコードを自動整形してくれる。</p></li> </ul> <h1 id="その他"><a href="#%E3%81%9D%E3%81%AE%E4%BB%96">その他</a></h1> <ul> <li><p>Log File Highlighter<br />  ログファイルの内容を色付きで表示してくれる。</p></li> <li><p>MySQL<br />  VSCodeでMySQLを使用可能にする。</p></li> <li><p>Rainbow CSV<br />  CSVファイルをカラムごとに色分けして表示してくれる。</p></li> <li><p>Regex Previewer<br />  正規表現の実行結果をプレビュー表示してくれる。</p></li> <li><p>SFTP<br />  サーバへ自動的にソースファイルをアップロードしてくれる。</p></li> </ul> <h1 id="【参考】"><a href="#%E3%80%90%E5%8F%82%E8%80%83%E3%80%91">【参考】</a></h1> <p>「Visual Studio Code」をインストールしてPHPコードのデバッグ環境を設定する方法<br /> <a target="_blank" rel="nofollow noopener" href="https://incloop.com/visualstudiocodeのデバッグ設定/">https://incloop.com/visualstudiocodeのデバッグ設定/</a></p> <p>Visual Studio Codeで作るPHP開発環境のおすすめ拡張機能17選<br /> <a target="_blank" rel="nofollow noopener" href="https://wonwon-eater.com/vscode-php-plugin/">https://wonwon-eater.com/vscode-php-plugin/</a></p> <p>VScodeの日本語化ができない 変わらない時の対処法[Visual Studio Code]<br /> <a target="_blank" rel="nofollow noopener" href="https://rabotiku-sato.com/vscode-japanese-setting">https://rabotiku-sato.com/vscode-japanese-setting</a></p> <p>vscodeでVue.jsを書くときに使っているプラグインとか<br /> <a target="_blank" rel="nofollow noopener" href="https://qiita.com/dayoshix/items/c61a75a971331418c348">https://qiita.com/dayoshix/items/c61a75a971331418c348</a></p> <p>【HTML編】Visual Studio Code おすすめプラグイン紹介 #02<br /> <a target="_blank" rel="nofollow noopener" href="https://so-da.tech/tech/vscode/vscd3/">https://so-da.tech/tech/vscode/vscd3/</a></p> <p>VSCodeのAuto Rename Tagで閉じタグも自動変更<br /> <a target="_blank" rel="nofollow noopener" href="https://tech.pjin.jp/blog/2020/04/27/vscode_extension_auto_rename_tag/">https://tech.pjin.jp/blog/2020/04/27/vscode_extension_auto_rename_tag/</a></p> <p>VSCode で HTML の文法チェックを行う拡張機能 HTMLHint<br /> <a target="_blank" rel="nofollow noopener" href="https://loumo.jp/archives/26229">https://loumo.jp/archives/26229</a></p> <p>VSCode拡張機能『indent-rainbow』でインデントを虹色にする方法<br /> <a target="_blank" rel="nofollow noopener" href="https://onedarling.site/programming/tool/vscode-indent-rainbow/">https://onedarling.site/programming/tool/vscode-indent-rainbow/</a></p> <p>【2020年版】VSCodeでhtml/css/jsの拡張機能おすすめ<br /> <a target="_blank" rel="nofollow noopener" href="https://uetani33.net/vscode-web-extensions/#toc_id_3_2">https://uetani33.net/vscode-web-extensions/#toc_id_3_2</a></p> <p>VSCode使い必見!?使って便利な Visual Studio Code 拡張機能10選<br /> <a target="_blank" rel="nofollow noopener" href="https://www.geekfeed.co.jp/geekblog/vscode_extension">https://www.geekfeed.co.jp/geekblog/vscode_extension</a></p> <p>【超便利】VSCodeでMySQLを利用する方法<br /> <a target="_blank" rel="nofollow noopener" href="https://newmtube07.com/vscode-mysql/">https://newmtube07.com/vscode-mysql/</a></p> <p>[Visual Studio Code] PHPのコードを整形する「php cs fixer」の設定<br /> <a target="_blank" rel="nofollow noopener" href="https://www.searchlight8.com/visual-studio-code-php/">https://www.searchlight8.com/visual-studio-code-php/</a></p> <p>VSCode(Visual Studio Code)でSFTP・FTP経由でファイルを自動アップロードや同期できる拡張機能「SFTP」が超便利<br /> <a target="_blank" rel="nofollow noopener" href="https://www.karelie.net/vscode-sftp/">https://www.karelie.net/vscode-sftp/</a></p> <p>Windows10でVisual Studio Code + vue-cliの開発環境構築メモ<br /> <a target="_blank" rel="nofollow noopener" href="https://belhb.hateblo.jp/entry/2020/08/08/142540">https://belhb.hateblo.jp/entry/2020/08/08/142540</a></p> <p>【2021.8.8 追加】<br /> LaravelでVisual Studio Codeを使う時に入れておきたい拡張機能3選<br /> <a target="_blank" rel="nofollow noopener" href="https://biz.addisteria.com/laravel-vscode/">https://biz.addisteria.com/laravel-vscode/</a></p> <p>Laravel blade formatter VSCode Extensionを作った<br /> <a target="_blank" rel="nofollow noopener" href="https://shufo.dev/2020/10/03/published-vscode-blade-formatter/">https://shufo.dev/2020/10/03/published-vscode-blade-formatter/</a></p> <p>VSCodeでBladeテンプレートを整形する<br /> <a target="_blank" rel="nofollow noopener" href="https://blog.nplpl.com/310">https://blog.nplpl.com/310</a></p> acmz tag:crieit.net,2005:PublicArticle/16679 2021-02-10T11:02:17+09:00 2021-02-10T11:02:17+09:00 https://crieit.net/posts/Laravel-Maximum-execution-time-of-30-seconds-exceeded LaravelでMaximum execution time of 30 seconds exceededが頻発する場合 <p>Laravelで下記のようなエラーが何分かごとに発生していた。</p> <pre><code>[2021-02-09 17:09:02] production.ERROR: Maximum execution time of 30 seconds exceeded {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalErrorException(code: 1): Maximum execution time of 30 seconds exceeded at /home/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php:73) [stacktrace] #0 {main} "} </code></pre> <p>ちなみに環境はPHP7.4、Laravel5.7とフレームワークはちょっと古め。最新ではもしかしたら全く同じ環境でも出ないのかもしれないし出るかもしれない。</p> <p>根本的な原因としては処理が重くて30秒で終わらず強制停止になってしまっていること。そのため停止位置は下記のようにばらつきがある。</p> <ul> <li>vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php</li> <li>vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php</li> <li>vendor/symfony/finder/Iterator/RecursiveDirectoryIterator</li> <li>vendor/symfony/finder/Iterator/DateRangeFilterIterator</li> </ul> <p>stacktraceも空のため、何をやっている途中で発生しているのかはわからない。</p> <h2 id="解決方法"><a href="#%E8%A7%A3%E6%B1%BA%E6%96%B9%E6%B3%95">解決方法</a></h2> <p>原因はわからないが、色々調べてみた情報から考えてみると、ファイルを扱いまくって重いところといったらセッション……? という疑惑が出てきたためセッションをファイルからデータベースに変更した。するとエラーが出なくなった。</p> <h2 id="原因"><a href="#%E5%8E%9F%E5%9B%A0">原因</a></h2> <p>恐らくアクセスが増えてセッション用のファイルが増えすぎると発生する……? 詳しいことはもう誰にもわからない。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/16396 2020-12-20T17:53:51+09:00 2020-12-20T17:53:51+09:00 https://crieit.net/posts/laravel6-x-bootstrap laravel6.xでbootstrapを使う <h2 id="laravel6.x以降にbootstrapを入れる"><a href="#laravel6.x%E4%BB%A5%E9%99%8D%E3%81%ABbootstrap%E3%82%92%E5%85%A5%E3%82%8C%E3%82%8B">laravel6.x以降にbootstrapを入れる</a></h2> <p>laravel6.xからは、bootstrapがデフォルトで入っていないので、自分で入れてあげる必要があるらしい。<br /> 調べたところ、以下のコマンドを実行すれば良さそう。</p> <pre><code class="bash">composer require laravel/ui php artisan ui bootstrap npm install && npm run dev </code></pre> <p>これでうまく行けばおしまい。</p> <h2 id="しかし現実は甘くなかった"><a href="#%E3%81%97%E3%81%8B%E3%81%97%E7%8F%BE%E5%AE%9F%E3%81%AF%E7%94%98%E3%81%8F%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F">しかし現実は甘くなかった</a></h2> <p><del>案の定</del><code>composer require</code>の時点でエラーになった。</p> <pre><code class="bash">Using version ^2.0 for laravel/ui ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Your requirements could not be resolved to an installable set of packages. Problem 1 - Conclusion: remove laravel/framework v6.18.1 - Conclusion: don't install laravel/framework v6.18.1 - laravel/ui 2.x-dev requires illuminate/filesystem ^7.0 -> satisfiable by illuminate/filesystem[7.x-dev, v7.0.0, v7.0.1, v7.0.2, v7.0.3, v7.0.4, v7.0.5, v7.0.6, v7.0.7, v7.0.8, v7.1.0, v7.1.1] # 以下略 </code></pre> <p>要は、「 laravel/ui2.0はLaravel7じゃないといけないけど、君の環境はそれを満たしてないよ!」とのこと。</p> <p><a target="_blank" rel="nofollow noopener" href="https://packagist.org/packages/laravel/ui">https://packagist.org/packages/laravel/ui</a><br /> ↑によると、それぞれの対応バージョンは以下のようになっている。</p> <div class="table-responsive"><table> <thead> <tr> <th>Version</th> <th>Laravel Version</th> </tr> </thead> <tbody> <tr> <td>1.x</td> <td>5.8, 6.x</td> </tr> <tr> <td>2.x</td> <td>7.x</td> </tr> <tr> <td>3.x</td> <td>8.x</td> </tr> </tbody> </table></div> <p>つまり、laravel6.xで使うには2.xではなくて1.xを入れないといけない。<br /> というわけで、以下のようにバージョンを明記してインストールし直し。</p> <pre><code class="bash">composer require laravel/ui:1.3.0 </code></pre> <p>次に、<code>/var/www/html/vendor/laravel/ui/src/Presets/Bootstrap.php</code>の中のパスを以下の様に変更</p> <pre><code>copy(__DIR__.'/bootstrap-stubs/_variables.scss', resource_path('assets/sass/_variables.scss')); copy(__DIR__.'/bootstrap-stubs/app.scss', resource_path('assets/sass/app.scss')); copy(__DIR__.'/bootstrap-stubs/bootstrap.js', resource_path('assets/js/bootstrap.js')); </code></pre> <p>これで再度</p> <pre><code class="bash">php artisan ui bootstrap npm install && npm run dev </code></pre> <p>これで入った。</p> みみみみみ tag:crieit.net,2005:PublicArticle/16210 2020-11-10T18:19:54+09:00 2020-11-10T18:22:30+09:00 https://crieit.net/posts/Apache-Laravel-Vue-js-Vuetify-web 【Apache Laravel Vue.js Vuetify】webアプリをスマホに対応させるためにやったこと <p>Apache+Laravel+Vue.js+Vuetify で作った社内ツールをスマホ対応したときに行った作業内容メモ。<br /> <del>ほんとにiosが嫌いになりそうだった</del></p> <p>対応ブラウザは、</p> <ul> <li>chrome(PC, Android, ios)</li> <li>safari(ios)</li> </ul> <h2 id="まずはiPhone、Androidのデバッグが出来るように準備する"><a href="#%E3%81%BE%E3%81%9A%E3%81%AFiPhone%E3%80%81Android%E3%81%AE%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E3%81%8C%E5%87%BA%E6%9D%A5%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E6%BA%96%E5%82%99%E3%81%99%E3%82%8B">まずはiPhone、Androidのデバッグが出来るように準備する</a></h2> <p>それぞれの端末を持っていれば、PCに繋いでデバッグができる!なんて素晴らしい。<br /> iosはiPhone以外にもiPad、iPod touch でも問題なし。<br /> それぞれ以下を参考に。</p> <p>Android:<a target="_blank" rel="nofollow noopener" href="https://qiita.com/hojishi/items/12b726f8b02ef3d713e4">https://qiita.com/hojishi/items/12b726f8b02ef3d713e4</a><br /> ios:<a target="_blank" rel="nofollow noopener" href="https://webkatu.com/archives/ios-safari-debug-on-windows/">https://webkatu.com/archives/ios-safari-debug-on-windows/</a></p> <h2 id="Polyfillを入れる"><a href="#Polyfill%E3%82%92%E5%85%A5%E3%82%8C%E3%82%8B">Polyfillを入れる</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://v2.vuetifyjs.com/ja/getting-started/browser-support/">Vuetifyの公式ドキュメント</a>に則って入れればOK。</p> <pre><code class="bash">npm install babel-polyfill --save npm install @babel/preset-env --save </code></pre> <p>インストール後、<br /> <code>import Vue from 'vue'</code> とか<br /> <code>import vuetify from '@/plugins/vuetify</code><br /> を書いているファイルに、<br /> <code>import 'babel-polyfill'</code> を追加。<br /> (自分の場合は <code>/resources/assets/js/app.js</code>)</p> <p>ルートディレクトリの .babelrcに、</p> <pre><code> { "presets": ["@babel/preset-env"] } </code></pre> <h2 id="対応していないjsを地道に直す"><a href="#%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84js%E3%82%92%E5%9C%B0%E9%81%93%E3%81%AB%E7%9B%B4%E3%81%99">対応していないjsを地道に直す</a></h2> <p>特に問題なければ、↑を行えば画面は表示されるはず…と思っていたのだが、画面が真っ白だった。</p> <p>エラーを調べると、どうやら正規表現で後読みを使っているのが原因みたいだったので、該当箇所を修正。<br /> (safariは後読みに対応していない)</p> <p>※書いている最中に気づいたけど、それってつまりうまくPolyfillが使えていなかったのでは…??</p> <h2 id="「Error: Network Error POST 応答を解析できません」を直す"><a href="#%E3%80%8CError%3A+Network+Error%E3%80%80POST++%E5%BF%9C%E7%AD%94%E3%82%92%E8%A7%A3%E6%9E%90%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93%E3%80%8D%E3%82%92%E7%9B%B4%E3%81%99">「Error: Network Error POST 応答を解析できません」を直す</a></h2> <p>iosのみ起きる謎現象。これに2日かかった…<br /> 自分は、Apacheの設定を変更で直った。</p> <pre><code><Directory "/var/www/html/public"> AllowOverride All # Allow open access: Header unset Upgrade ←これを追加 </Directory> </code></pre> <p>とりあえずここまでで画面が開けるようになりました。<br /> 以降は細かい部分です。</p> <h2 id="スクロールを入れたくないのにスマホだと入ってしまう"><a href="#%E3%82%B9%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%AB%E3%82%92%E5%85%A5%E3%82%8C%E3%81%9F%E3%81%8F%E3%81%AA%E3%81%84%E3%81%AE%E3%81%AB%E3%82%B9%E3%83%9E%E3%83%9B%E3%81%A0%E3%81%A8%E5%85%A5%E3%81%A3%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86">スクロールを入れたくないのにスマホだと入ってしまう</a></h2> <p>webアプリ全体にスクロールを入れたくない場合、bodyに<code>height:100%</code>とか入れればPCでは大丈夫だったりしたんですが、<br /> スマホだとどうにも謎のスクロールが入ってしまうので、以下のように対応。</p> <pre><code class="html"><html id="content">  … </code></pre> <p>※jsでhtmlのところにstyleを指定する方法がわからなかったのでid属性を無理やり、、、</p> <pre><code class="js">const windowHeight = window.innerHeight; // windowの高さを取得 // <html>の高さを、windowsの高さいっぱいに設定 document.getElementById("content").style.height = windowHeight + "px"; // bodyはheight:100% document.body.style.height = "100%"; // スクロールバー非表示 // スマホのときはbodyに、PCのときはhtmlにかけないと反映されないっぽいので分ける const isSP = /iPhone|iPod|iPad|Android/i.test(navigator.userAgent); if (isSP) { document.body.style.overflowY = "hidden"; } else { document.getElementById("content").style.overflowY = "hidden"; } </code></pre> <p>…無理矢理感半端ないけど、ひとまずこれでPCでもスマホでも画面いっぱいでコンテンツが収まるようになった。</p> <h2 id="iosだけ、キーボードのenterでボタンクリック判定されてしまう"><a href="#ios%E3%81%A0%E3%81%91%E3%80%81%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%81%AEenter%E3%81%A7%E3%83%9C%E3%82%BF%E3%83%B3%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E5%88%A4%E5%AE%9A%E3%81%95%E3%82%8C%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86">iosだけ、キーボードのenterでボタンクリック判定されてしまう</a></h2> <p>PCやAndroidでは大丈夫なのに、iosだけ起きる謎現象。<br /> 改行する度にボタンが押されて送信されるという、、、、</p> <p>※単純にv-formのsubmitイベントが発火してしまっている場合は、<a target="_blank" rel="nofollow noopener" href="https://riotz.works/articles/lopburny/2019/07/31/page-reload-issue-by-implicit-submission/">こちら</a>を参考に。</p> <p>根本的な原因はわからなかったため、<br /> 入力文字が空欄・改行のみの場合は、ボタンクリックで呼ばれる処理が走らないようにした。</p> <pre><code class="html"><textarea v-model="inputText"></textarea> <v-btn @click="submit()">送信</v-btn> </code></pre> <pre><code class="js"><br />data: () => ({ inputText: "", }), computed: { /** * 空文字判定 */ isTextEmpty() { return !this.inputText || !this.inputText.match(/\S/g); }, }, methods: { submit() { if (this.isTextEmpty) return; // 以下送信処理 } } </code></pre> <h2 id="iosだけファイルアップロードができない"><a href="#ios%E3%81%A0%E3%81%91%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84">iosだけファイルアップロードができない</a></h2> <p>ファイル選択のダイアルボックスを開く→ファイルを選択→アップロード<br /> という流れのとき、iosだけダイアルボックスが開かないという謎現象。<br /> エラーも出ない…</p> <p>調べてみたら、どうやら<code>input.onchange</code>が動いていないようだった。</p> <pre><code class="javascript">function uplod() { return new Promise(resolve => { const input = document.createElement('input'); input.type = "file"; input.multiple = false; input.accept = "image/gif,image/jpeg,image/png"; input.onchange = event => { var file = event.target.files[0]; resolve(file); }; input.click(); }); } </code></pre> <p>ios以外は↑でも動いたが、どうやらiosではちゃんと<code><input></code>要素をDOMに追加してあげないといけないらしい。<br /> 参考:<a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/47664777/javascript-file-input-onchange-not-working-ios-safari-only">https://stackoverflow.com/questions/47664777/javascript-file-input-onchange-not-working-ios-safari-only</a></p> <p>というわけで、以下のように修正</p> <pre><code class="javascript">function uplod() { return new Promise(resolve => { const input = document.createElement('input'); input.type = 'file'; input.multiple = false; input.accept = "image/gif,image/jpeg,image/png"; document.body.appendChild(input); // ←DOMに追加 input.onchange = event => { var file = event.target.files[0]; document.body.removeChild(input); // ←DOMから削除 resolve(file); }; input.click(); }); } </code></pre> <h2 id="iosだけ画像が縦に伸びる時"><a href="#ios%E3%81%A0%E3%81%91%E7%94%BB%E5%83%8F%E3%81%8C%E7%B8%A6%E3%81%AB%E4%BC%B8%E3%81%B3%E3%82%8B%E6%99%82">iosだけ画像が縦に伸びる時</a></h2> <p>これは別記事にもメモしてあるが、<br /> <code>display:flex;</code>を指定している箇所に、<code>align-items: flex-start;</code>を追記するだけ。<br /> 参考:<a target="_blank" rel="nofollow noopener" href="https://nichiyogogo.com/image-looks-stretched/">https://nichiyogogo.com/image-looks-stretched/</a></p> <h2 id="iosだけ、heightを指定した要素内の「overflow-y: visible scroll;」が効かない"><a href="#ios%E3%81%A0%E3%81%91%E3%80%81height%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%E5%86%85%E3%81%AE%E3%80%8Coverflow-y%3A+visible+scroll%3B%E3%80%8D%E3%81%8C%E5%8A%B9%E3%81%8B%E3%81%AA%E3%81%84">iosだけ、heightを指定した要素内の「overflow-y: visible scroll;」が効かない</a></h2> <p>これもiosの一部で起きる現象。<br /> safariのバージョンの問題かもしれない。</p> <p>ますは<a target="_blank" rel="nofollow noopener" href="https://shanabrian.com/web/html-css-js-technics/css-ios-safari-02.php">ここ</a>を参考に修正。<br /> 自分はこのときにも頑なに<code>overflow-y: visible scrol</code>と書き続けていたら直らず、<br /> 素直に <code>overflow-y:auto;</code> にするだけで解決…。</p> <h2 id="おわり"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A">おわり</a></h2> <p>ほとんどios対応ですね。<br /> Androidはグリッドをちゃんと設定して、表示崩れしないようにだけしてあげれば殆ど動きました。<br /> マジでiosとsafariが嫌いになりそうだった…。</p> みみみみみ tag:crieit.net,2005:PublicArticle/16151 2020-10-19T18:05:31+09:00 2020-10-19T18:05:31+09:00 https://crieit.net/posts/Laravel-Pusher-The-data-content-of-this-event-exceeds-the-allowed-maximum 【Laravel+Pusher】The data content of this event exceeds the allowed maximum のエラーが出た時 <p><a target="_blank" rel="nofollow noopener" href="https://pusher.com/docs/channels/server_api/http-api#publishing-events">https://pusher.com/docs/channels/server_api/http-api#publishing-events</a></p> <p>↑にも書いてあるが、<br /> The data content (POST body) of events must be smaller than 10kB.<br /> (イベントのデータコンテンツ(POST本文)は10kB未満である必要があります。)</p> <p>とのことなので、<br /> イベントに何でもかんでもぶち込むとエラーになるっぽい。</p> <h1 id="解決策"><a href="#%E8%A7%A3%E6%B1%BA%E7%AD%96">解決策</a></h1> <pre><code class="php">$event = [ "eventType" => 1, "id" => 1, "content" => [...] // ←ここのサイズが大きかった ]; event(new PusherEvent($event)); </code></pre> <p>↑これをvueで受け取って、</p> <pre><code class="js">this.content = event.content </code></pre> <p>のようにしていたのを、</p> <pre><code class="php">$event = [ "eventType" => 1, "id" => 1, ]; event(new PusherEvent($event)); </code></pre> <p>イベントタイプとデータのidのみ渡すように修正</p> <pre><code class="js">async getContent(id) { // ajaxでデータ取得 }, ... ver content = await getContent(event.id); this.content = content </code></pre> <p>ajaxでデータを取得し、それを反映</p> <p>という風に直したら解決。</p> <p>もちろん仕様によってはある程度制御をしなければ、<br /> ログインしているユーザー人数だけgetContent()が呼ばれてまた別のエラーになるので、<br /> そこは適宜対応が必要。</p> みみみみみ tag:crieit.net,2005:PublicArticle/16146 2020-10-19T17:50:23+09:00 2020-10-19T17:50:23+09:00 https://crieit.net/posts/Laravel-feature 【Laravel】feature テスト レスポンスのデバッグ <pre><code class="php">$response = $this->get('/'); $response->assertStatus(200) </code></pre> <p>みたいなテストをするとき、レスポンスの中身をみたい場面があった。</p> <pre><code class="php">$response->dumpHeaders(); $response->dumpSession(); $response->dump(); </code></pre> <p>これで取得できる!<br /> ちゃんとドキュメントにも書いてあった。<br /> <a target="_blank" rel="nofollow noopener" href="https://readouble.com/laravel/6.x/ja/http-tests.html">https://readouble.com/laravel/6.x/ja/http-tests.html</a></p> <p>もっと早く気付けたら良かった~~~</p> みみみみみ tag:crieit.net,2005:PublicArticle/16143 2020-10-19T17:44:29+09:00 2020-10-19T17:44:29+09:00 https://crieit.net/posts/Laravel-Debugbar-Telescope-Mixed-Content Laravel  DebugbarやTelescopeを使おうとするとMixed Contentでエラーになる <p>AppServiceProvider.phpのboot()中に、</p> <pre><code class="php">if (config('app.env') === 'production') { \URL::forceScheme('https'); } </code></pre> <p>を入れるだけで解決!</p> みみみみみ tag:crieit.net,2005:PublicArticle/15953 2020-06-14T15:24:10+09:00 2021-05-17T21:59:25+09:00 https://crieit.net/posts/introducing-portaldots 大学祭の参加団体向けウェブシステムをOSS化してみた <p><a href="https://crieit.now.sh/upload_images/658e61a355af5e8c729368deafa1ffd35ee268532719f.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/658e61a355af5e8c729368deafa1ffd35ee268532719f.png?mw=700" alt="main_screenshot.png" /></a></p> <h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2> <p>大学祭では、たくさんの参加団体(サークル・部活)が模擬店などの企画を出店し、盛り上げています。</p> <p>大学祭を成功させるには、実行委員会と参加団体の間の連携が欠かせません。連携するための方法として、実行委員会では、参加団体からの「各種申請」を受け付けています。例えば、大学祭当日に配布されるパンフレットに掲載する内容を参加団体から募集する必要があります。また、実行委員会が貸し出す備品の申請を受け付けることもあります。</p> <p>こうした申請受付業務は、多くの大学祭では紙による受付であったり、メールや Google フォームでの受付を行っているところが多いかと思います。</p> <p>紙やメールによる受付の場合、紙・メールに書かれた内容を1枚1枚Excelに入力していく手間がかかります。受付方法によっては対面での対応が必要となり、昨今の状況下では厳しいものがあります。<br /> (そもそも、今年の秋冬に開催される学園祭でも、予定通り開催できるかどうか怪しいところではありますが……)</p> <p>そのような中、私は<strong>大学祭の各種申請などを受け付けるウェブシステムを開発し、今年になってそれを OSS 化</strong>してみました。</p> <ul> <li>GitHub : <a target="_blank" rel="nofollow noopener" href="https://github.com/portal-dots/PortalDots">https://github.com/portal-dots/PortalDots</a></li> <li>PortalDots 公式ウェブサイト(2020/11/30 公開) : <a target="_blank" rel="nofollow noopener" href="https://dots.soji.dev">https://dots.soji.dev</a></li> </ul> <h2 id="私は誰?"><a href="#%E7%A7%81%E3%81%AF%E8%AA%B0%EF%BC%9F">私は誰?</a></h2> <p>私は、東京理科大学の野田キャンパスに通う大学生です。大学名こそ「東京」とついていますが、「野田」は「千葉県」にあります。そんな野田キャンパスで開催される学園祭「野田地区理大祭」の実行委員をしていました。</p> <p>実行委員時代は、PortalDots の開発のほか、公式ウェブサイト・パンフレットのデザイン・実装なども行っていました。</p> <ul> <li>野田地区理大祭公式ウェブサイト : <a target="_blank" rel="nofollow noopener" href="https://nodaridaisai.com/">https://nodaridaisai.com/</a></li> </ul> <h2 id="参加団体向けウェブシステム「PortalDots」"><a href="#%E5%8F%82%E5%8A%A0%E5%9B%A3%E4%BD%93%E5%90%91%E3%81%91%E3%82%A6%E3%82%A7%E3%83%96%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%80%8CPortalDots%E3%80%8D">参加団体向けウェブシステム「PortalDots」</a></h2> <p><a href="https://crieit.now.sh/upload_images/21e25532d98d0eaccd44964220ac8f765ee5e5b35aaeb.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/21e25532d98d0eaccd44964220ac8f765ee5e5b35aaeb.png?mw=700" height="40" alt="PortalDotsのロゴ"></a></p> <ul> <li>GitHub : <a target="_blank" rel="nofollow noopener" href="https://github.com/portal-dots/PortalDots">https://github.com/portal-dots/PortalDots</a> <ul> <li>よろしければぜひ Star お願いします…!</li> </ul></li> </ul> <h3 id="開発環境の動かし方"><a href="#%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%81%AE%E5%8B%95%E3%81%8B%E3%81%97%E6%96%B9">開発環境の動かし方</a></h3> <p>開発環境を動かすには Git、PHP(7.4以上)、Node.js、Yarn、Docker がセットアップ済みである必要があります。</p> <p><strong>2020/06/27 追記</strong> : コマンドの実行順序が間違っていたので修正しました。<br /> <strong>2021/05/17 追記</strong> : 開発環境の起動方法の変更を反映しました。</p> <pre><code class="bash">$ git clone [email protected]:portal-dots/PortalDots.git $ cd PortalDots/ # 必要な Node.js パッケージをインストール # ※ エラーが表示される場合は、Node.js を最新バージョンにアップグレードした上で、再度 yarn install を実行してください。 $ yarn install # 設定ファイルを作成 $ cp .env.example .env $ php artisan key:generate # 開発環境を起動する $ yarn docker # マイグレーション(データベースのセットアップ) $ yarn migrate # Docker コンテナ内で必要な PHP パッケージをインストール $ yarn docker-bash $ composer install $ exit # フロントエンド開発サーバーの起動 $ yarn hot # → ブラウザで http://localhost にアクセスすると、PortalDots の開発環境が起動する # → フロントエンド開発サーバーを終了するには Ctrl + C を押す # 開発環境を停止する $ yarn docker-stop </code></pre> <h3 id="トップページ"><a href="#%E3%83%88%E3%83%83%E3%83%97%E3%83%9A%E3%83%BC%E3%82%B8">トップページ</a></h3> <p>トップページでは、参加団体向け説明会の次回日程の表示機能や、各種お知らせの閲覧、配布資料のダウンロードなどができるようになっています。</p> <p>企画参加登録の受付期間中は、提出している参加登録の受理状況も確認できます。</p> <p><a href="https://crieit.now.sh/upload_images/42a053619c899ae5db5c6cbc04f3d5eb5ee266d90c32e.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/42a053619c899ae5db5c6cbc04f3d5eb5ee266d90c32e.png?mw=700" alt="screenshot_home.png" /></a></p> <h3 id="企画参加登録"><a href="#%E4%BC%81%E7%94%BB%E5%8F%82%E5%8A%A0%E7%99%BB%E9%8C%B2">企画参加登録</a></h3> <p>学園祭への企画エントリーもウェブから可能です。</p> <p><a href="https://crieit.now.sh/upload_images/942b1908f49e4c9db2e9466e90b229eb5ee267d059776.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/942b1908f49e4c9db2e9466e90b229eb5ee267d059776.png?mw=700" alt="screenshot_circle_register.png" /></a></p> <h3 id="申請フォーム"><a href="#%E7%94%B3%E8%AB%8B%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0">申請フォーム</a></h3> <p>大学祭の参加団体は、このようなフォームからパンフレット掲載内容などの情報を委員会へ提出することができます。</p> <p>受付期間を設定することも可能です。</p> <p><a href="https://crieit.now.sh/upload_images/98cb9cc9bf6a8e93ec300a84080c92345ee2679b7ac94.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/98cb9cc9bf6a8e93ec300a84080c92345ee2679b7ac94.png?mw=700" alt="image.png" /></a></p> <h3 id="フォームエディター(Vue.js 製)"><a href="#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF%E3%83%BC%28Vue.js+%E8%A3%BD%29">フォームエディター(Vue.js 製)</a></h3> <p>「フォームエディター」は <strong>PortalDots の目玉機能(?)</strong> です。</p> <p>実行委員は、各種申請を受け付けるフォームを Google フォームのようなノリで作成することができるようになっています。</p> <p>「じゃあ、Google フォーム使えば良いのでは?」と思われるかもしれませんが、Google フォームではログイン・新規登録機能(※1)は利用できない上、回答内容の編集が容易でなかったり(※2)、<strong>1団体あたり1回答までに制限できなかったり</strong>(※3)するなど、大学祭の申請フォームとしては不便なところもあります。</p> <p>PortalDots の「フォームエディター」で作成できるフォームは、回答受付期間を設定できたり、1企画につき1回まで回答可能という設定ができたり、あとから回答を簡単に修正できたりします。</p> <p>※1 : Google フォームでも、一応 Google アカウントでのログインを必須にすることはできます</p> <p>※2 : Google フォームでも、回答者に回答の編集を許可することはできます。ただ、編集用の URL を紛失してしまうと編集できなくなってしまいます</p> <p>※3 : Google フォームでは、<strong>1ユーザーあたり</strong>の回答数を制限できます。<strong>1団体あたり</strong>のような制限をかけるのは難しいと思われます</p> <p><a href="https://crieit.now.sh/upload_images/fd82398a4a47ec43ce8edc68a27147cd5ee2676b1a9f0.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/fd82398a4a47ec43ce8edc68a27147cd5ee2676b1a9f0.png?mw=700" alt="screenshot_form_editor.png" /></a></p> <blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">参加企画に提出してもらう各種申請もウェブフォームで受け付けられます。動画のように設問ぐりぐりできます。 <a target="_blank" rel="nofollow noopener" href="https://t.co/5rVFRVnUPd">pic.twitter.com/5rVFRVnUPd</a></p>— Soji — PortalDots (@sofpyon) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/sofpyon/status/1271122648928403456?ref_src=twsrc%5Etfw">June 11, 2020</a></blockquote> <h2 id="CodeIgniter から Laravel への移行途中です → 完了しました!"><a href="#CodeIgniter+%E3%81%8B%E3%82%89+Laravel+%E3%81%B8%E3%81%AE%E7%A7%BB%E8%A1%8C%E9%80%94%E4%B8%AD%E3%81%A7%E3%81%99+%E2%86%92+%E5%AE%8C%E4%BA%86%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%EF%BC%81">CodeIgniter から Laravel への移行途中です → 完了しました!</a></h2> <p><strong>2021/05/17追記 : 先日、CodeIgniter のコードを全て削除し、Laravel へ完全移行しました!</strong></p> <blockquote class="twitter-tweet" data-lang="ja" data-dnt="true"><p lang="ja" dir="ltr">ついに <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/PortalDots?src=hash&ref_src=twsrc%5Etfw">#PortalDots</a> のコードが、悲願の 100% Laravel 化達成しました…!CodeIgniter 消します! <a target="_blank" rel="nofollow noopener" href="https://t.co/vt1RKYDfcL">pic.twitter.com/vt1RKYDfcL</a></p>— Soji (@sofpyon) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/sofpyon/status/1388511050224472066?ref_src=twsrc%5Etfw">2021年5月1日</a></blockquote> <hr /> <p>(以下、追記前)</p> <p>現在、「CodeIgniter」と「Laravel」という、2つのウェブフレームワークを混在して使用しています。</p> <p>元々 PortalDots は、私がウェブフレームワーク初心者のころ(大学1年の夏)に開発を始めた物でした。それ以前はフレームワークという物自体を使ったことがなく、プレーンな PHP コードでしか書いたことがなかったのですが、「CodeIgniter というフレームワークは簡単」だという話を聞き、試しに PortalDots の開発で使ってみたのでした。</p> <p>しかし、CodeIgniter の機能は貧弱である点や、なるべくメインストリームにあるフレームワークを使ったほうが今後のメンテナンスがしやすいだろうということで、Laravel への移行をはじめました。</p> <p>2020年6月現在、CodeIgniter が使われているのは「スタッフモード」(実行委員用のページ)のみとなっており、それ以外のページは Laravel に移行済みとなっています。</p> <h2 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h2> <p>OSS 化したので PortalDots はどなたでも自由にお使いいただけるようになりました。</p> <p>学園祭実行委員会に所属しており、かつプログラミング経験のある方がいましたら、ぜひ使っていただきたいです。また、学園祭関係者でなくても、お試しとして実物を触っていただけると嬉しいです!</p> <ul> <li>GitHub : <a target="_blank" rel="nofollow noopener" href="https://github.com/portal-dots/PortalDots">https://github.com/portal-dots/PortalDots</a></li> <li>PortalDots 公式ウェブサイト(2020/11/30 公開) : <a target="_blank" rel="nofollow noopener" href="https://dots.soji.dev">https://dots.soji.dev</a></li> </ul> SofPyon tag:crieit.net,2005:PublicArticle/15900 2020-05-17T06:58:19+09:00 2023-07-07T18:45:02+09:00 https://crieit.net/posts/pay-web-service-release-knowledge-summary 有料のWebサービスをリリースするまでに取り組んだこと・知見をまとめました【個人開発】 <h1 id="1. 作ったサービス"><a href="#1.+%E4%BD%9C%E3%81%A3%E3%81%9F%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9">1. 作ったサービス</a></h1> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117180/dbadeb45-61fc-48d6-3a8c-d7908b6270d8.png" alt="twikeshi-ogp.png" /></p> <p><strong>ツイ消し職人 | ツイ消しツールの決定版!</strong><br /> <strong><a target="_blank" rel="nofollow noopener" href="https://twikeshi.net/">https://twikeshi.net/</a></strong></p> <blockquote> <p>ツイ消しツールの決定版!<br /> ツイ消し職人は 今までのツイートを全消しできる「ツイート一括削除ツール」 です。<br /> 3200件を超える大量のツイートを全て削除できます。<br /> 無料のツールなどでうまく削除できなかった方は是非ご利用ください。<br /> 既存のフォロワーをそのままに、Twitterをやり直すことができます。</p> </blockquote> <h1 id="2. 自己紹介"><a href="#2.+%E8%87%AA%E5%B7%B1%E7%B4%B9%E4%BB%8B">2. 自己紹介</a></h1> <p>こんにちは、ひろと申します。<br /> 現在はフリーランスエンジニアとして活動しています。</p> <h1 id="3. なぜ作ったのか"><a href="#3.+%E3%81%AA%E3%81%9C%E4%BD%9C%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B">3. なぜ作ったのか</a></h1> <p>私は2020年4月にフリーランスとして独立しました。<br /> それに伴い、学生時代から使っていたTwitterアカウントの運用を変えようと思い、今までのツイートを削除してやり直すことにしました。<br /> アカウントを作り直す選択肢もあったのですが、フォロワーを減らしたくなかったため、ツイ消しの道を選びました。<br /> 調べてみるとツイートの一括削除ツールがいくつか見つかったため、それを使ってツイ消しをすることにしました。</p> <p>しかし、<strong>既存のツールではツイートの削除ができませんでした。</strong><br /> 私の今までのツイート数は<strong>19万件</strong>で、Twitterアーカイブをダウンロードしたところzipファイルのサイズは<strong>31GB</strong>。<br /> 私が<strong>ツイ廃</strong>だったのが全ての原因です。</p> <p>普通のツイ消しサービスは、API制限の関係で3,200ツイートが削除の上限となってしまいます。私の19万ツイートに対してはあまりに無力すぎました。</p> <p>もちろん、API制限を回避するためにTwitterアーカイブをアップロードして削除を行うサービスもあります。<br /> しかし、31GBのzipファイルを送りつけると必ず500エラーが返ってきてしまい、私の試した範囲では、まともに動くものはありませんでした。海外の有料サービスでさえダメでした。(具体的なサービス名は出しませんが、日本円で1,600円払いました。手痛い出費です)</p> <p>そこで私は、「ツイ廃でもツイートを削除できるサービス」が必要だと思い、ツイ消し職人の開発を始めました。</p> <h1 id="4. リリースするまでに取り組んだこと"><a href="#4.+%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%81%99%E3%82%8B%E3%81%BE%E3%81%A7%E3%81%AB%E5%8F%96%E3%82%8A%E7%B5%84%E3%82%93%E3%81%A0%E3%81%93%E3%81%A8">4. リリースするまでに取り組んだこと</a></h1> <p>取り組んだ全てのことを記載しています。</p> <h2 id="一. サービスの命名"><a href="#%E4%B8%80.+%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E5%91%BD%E5%90%8D">一. サービスの命名</a></h2> <p>最初は「ツイートクリーナー」という名前にしていました。<br /> 開発中盤に「ツイ消し職人」という名前を思いつき、変更しました。<br /> ランサーズなどで名前を募集するのも良いと思います。</p> <h2 id="二. ドメインの取得"><a href="#%E4%BA%8C.+%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E5%8F%96%E5%BE%97">二. ドメインの取得</a></h2> <p>ムームードメインでtwikeshi.netを取得しました。<br /> 欲しいドメインが埋まっている場合は、twikeshi-app.netのように工夫するのもオススメです。</p> <h2 id="三. 商標登録"><a href="#%E4%B8%89.+%E5%95%86%E6%A8%99%E7%99%BB%E9%8C%B2">三. 商標登録</a></h2> <p>登録しました。<br /> 今は<a target="_blank" rel="nofollow noopener" href="https://toreru.jp/">Toreru</a>などの便利なサービスがあり、ものすごく簡単に出願できます。<br /> 48,000円で5年間有効になります。<br /> 商標権の取る取らないを選択するのは自由ですが、後から商標を第三者に取得されて商標権の侵害警告を受けた場合、サービス名やドメインを変えなければならないリスクがあることは認識しておく必要があります。</p> <h2 id="四. プライシング"><a href="#%E5%9B%9B.+%E3%83%97%E3%83%A9%E3%82%A4%E3%82%B7%E3%83%B3%E3%82%B0">四. プライシング</a></h2> <p>海外の同じようなサービスを参考に値付けを行いました。<br /> 現在は700円(税込)で提供しています。</p> <p>その後、プライシングに関する本を3冊読んで(<a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/gp/product/B07KWRPBP9/">この本</a>と<a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/gp/product/B013JEK6YS/">この本</a>と<a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/gp/product/B077S7BDD9/">この本</a>)考え方が変わったので、そのうち値上げするかもしれません。</p> <p><strong>間違っても、本来ターゲットでない人を取り込むために値下げするのはやめてください</strong>。<br /> 例えば、私は友人達に「ツイ消し職人の適正価格はいくらだと思う?」と質問をすると、2人が「100円」と答えました。<br /> しかし、断言しますが彼らは<strong>100円でも絶対に利用しません</strong>。何故ならば、彼らはこのツールの価値を理解していないからです。ツイ消しをしようと思ったことがない人に相場感を聞いても意味がありません。<br /> 逆に、本っっ当にツイ消しをしたくて困っている人からすれば、このツールが例え1万円でも喜んでお金を払うはずです。</p> <h2 id="五. 技術選定"><a href="#%E4%BA%94.+%E6%8A%80%E8%A1%93%E9%81%B8%E5%AE%9A">五. 技術選定</a></h2> <h3 id="1. バックエンド"><a href="#1.+%E3%83%90%E3%83%83%E3%82%AF%E3%82%A8%E3%83%B3%E3%83%89">1. バックエンド</a></h3> <p>バックエンドはLaravelで開発しました。<br /> Laravelはコードもドキュメントも読みやすいため、使っていて楽しいですね。</p> <div class="table-responsive"><table> <thead> <tr> <th align="left">役割</th> <th align="left">技術</th> </tr> </thead> <tbody> <tr> <td align="left">PHPフレームワーク</td> <td align="left">Laravel</td> </tr> <tr> <td align="left">データベース</td> <td align="left">MySQL</td> </tr> <tr> <td align="left">Twitterログイン</td> <td align="left">Laravel Socialite</td> </tr> <tr> <td align="left">Twitter APIライブラリ</td> <td align="left">TwitterOAuth</td> </tr> <tr> <td align="left">メール送信</td> <td align="left">SendGrid</td> </tr> </tbody> </table></div> <h3 id="2. フロントエンド"><a href="#2.+%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89">2. フロントエンド</a></h3> <p>CSSフレームワークにはMaterializeを採用しました。初めて使ったのですが、ドキュメントが分かりやすく情報量も多いのでオススメです。<br /> 今回はフロントで処理をする必要が無かったので、基本的にJavaScriptは使っていません。ファイルアップロードの画面は、アニメーションを付けるためにVue.jsを使いました。Vue.jsは以前から使っていたので、特に困ることはありませんでした。<br /> 次はNuxt.jsに挑戦するために勉強中です。</p> <div class="table-responsive"><table> <thead> <tr> <th align="left">役割</th> <th align="left">技術</th> </tr> </thead> <tbody> <tr> <td align="left">CSSフレームワーク</td> <td align="left">Materialize</td> </tr> <tr> <td align="left">JavaScriptフレームワーク</td> <td align="left">Vue.js</td> </tr> <tr> <td align="left">決済</td> <td align="left">Stripe Checkout</td> </tr> </tbody> </table></div> <h3 id="3. インフラ"><a href="#3.+%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9">3. インフラ</a></h3> <p>サーバーにはレンタルサーバーを採用しています。</p> <div class="table-responsive"><table> <thead> <tr> <th align="left">役割</th> <th align="left">技術</th> </tr> </thead> <tbody> <tr> <td align="left">レンタルサーバー</td> <td align="left">エックスサーバー</td> </tr> </tbody> </table></div> <p>Heroku / VPS / AWS EC2 / GCP App Engineなどの選択肢もありましたが、主にコストと運用の観点から除外しました。個人開発は自分でインフラを選べるのが良いですね。<br /> 今後もどんどんサービスを作っていく予定なので、サーバー費がかさむのはイヤだし、サービスを作る度に環境を構築するのも避けたかったのです。</p> <p>もちろん要件によってはレンタルサーバーが使えない場合もあります(ミドルウェアの設定変更や追加インストールが必要な場合など)。</p> <p>例えば、FFmpegを使って動画のエンコード等を行う場合です。<br /> まずrootが使えないのでインストールができません。自前でmakeして無理やり手動インストールすることも不可能ではなさそうですが、なるべく避けたいところです。また、動画のエンコード処理はCPUを食うので、運営に利用を停止される可能性があります。</p> <p>このようにrootユーザーが使えないと困る場合は、状況に応じて各サービスを比較検討しましょう。<br /> サーバーはHerokuだけどストレージにはS3を使って、DBにはCloud SQLを使うといったトリッキーなこともできます。柔軟な発想で最適な構成を作りましょう。</p> <p>参考に、私の考える主なインフラサービスのメリット・デメリットをまとめておきます。<br /> ※App Engineは詳しくないので簡易的な記載になってます</p> <div class="table-responsive"><table> <thead> <tr> <th align="left">インフラサービス</th> <th align="left">メリット</th> <th align="left">デメリット</th> </tr> </thead> <tbody> <tr> <td align="left">VPS(IaaS)</td> <td align="left">・安い・root使える</td> <td align="left">・借りる度にお金がかさむ・環境構築や設定が必要</td> </tr> <tr> <td align="left">EC2(IaaS)</td> <td align="left">・root使える・マイクロサービス沢山ある</td> <td align="left">・高い・借りる度にお金がかさむ・環境構築や設定が必要</td> </tr> <tr> <td align="left">App Engine(PaaS)</td> <td align="left">・環境構築不要</td> <td align="left">・高い・借りる度にお金がかさむ</td> </tr> <tr> <td align="left">Heroku(PaaS)</td> <td align="left">・安い・環境構築不要</td> <td align="left">・借りる度にお金がかさむ・30秒タイムアウト辛い</td> </tr> <tr> <td align="left">レンタルサーバー(ほぼPaaS)</td> <td align="left">・安い・1台でアプリ沢山動かせる・環境構築ほぼ不要</td> <td align="left">・root使えない</td> </tr> </tbody> </table></div> <h2 id="六. 設計"><a href="#%E5%85%AD.+%E8%A8%AD%E8%A8%88">六. 設計</a></h2> <p>小規模なサービスなので、ここにはほぼ時間をかけていません。<br /> ワイヤーフレームなどは作らず、実際に画面をコーディングしてレイアウトを決めました。<br /> DB設計もパパッと考えて終わり。<br /> 開発の中で必要になったときに都度、テーブルやカラム・画面を増やしていきました。<br /> サービスによっては色々な機能を思いつくと思いますが、まずはスモールスタートでリリースすることをゴールにしましょう。</p> <h2 id="七. 開発"><a href="#%E4%B8%83.+%E9%96%8B%E7%99%BA">七. 開発</a></h2> <p>一番時間をかけたのはこの工程です。<br /> 他の仕事が並行していたため正確ではありませんが、全体で2〜3週間はかかったと思います。<br /> 伝えたい情報がある場合はコメントを書いています。<br /> 有料サービスのみ必要になる項目には「☆」を付けています。</p> <h3 id="1. サービスの機能開発"><a href="#1.+%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E6%A9%9F%E8%83%BD%E9%96%8B%E7%99%BA">1. サービスの機能開発</a></h3> <h4 id="一. Twitterログイン"><a href="#%E4%B8%80.+Twitter%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3">一. Twitterログイン</a></h4> <p>ツイ消し職人では、決済完了時とツイート削除完了時に確認メールを送信しています。<br /> そのため、Twitter AppのAdditional permissionsとして、Request email addressにチェックを入れています。</p> <h4 id="二. ☆決済"><a href="#%E4%BA%8C.+%E2%98%86%E6%B1%BA%E6%B8%88">二. ☆決済</a></h4> <p>Stripe Checkoutは神。<br /> JavaScriptをちょろっと書くだけで決済を提供できます。返金もボタンポチるだけです。<br /> 週次で売上を銀行口座に入金してくれるところも良いですね。至れり尽くせり。<br /> ツイ消し職人はクレジットカード、Google Pay、Apple Payに対応しています。</p> <h4 id="三. アーカイブアップロード"><a href="#%E4%B8%89.+%E3%82%A2%E3%83%BC%E3%82%AB%E3%82%A4%E3%83%96%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89">三. アーカイブアップロード</a></h4> <p>Twitterが生成したデータを読み取らないといけないので、アーカイブのどのファイルに何の情報があるのかを全て自分で調べました。<br /> そして、ツイートの削除に本当に必要なファイルだけをアップロードさせることで、ファイルサイズを31GB→200MBまで減らすことができました。</p> <p>アーカイブからはツイートの削除に必要な情報を正規表現で抽出する必要があります。<br /> 最初は、JavaScriptを使いフロント側で情報を抽出し、サーバーには最低限のデータだけ送るようにする予定だったのですが、少し時間がかかりそうだったので諦めました。</p> <p>FileReader.readAsText()に100MBのファイルを食わせるとクラッシュしてしまうことが判明し、ファイルをチャンクして処理する必要が出てきたためです。<br /> コンソールにエラーは出力されず、サイレントでクラッシュするので問題の特定に時間がかかりました。<br /> サーバ側で抽出処理をやっても特に問題はないので、サーバ側で処理するようにしました。</p> <h4 id="四. ツイート削除"><a href="#%E5%9B%9B.+%E3%83%84%E3%82%A4%E3%83%BC%E3%83%88%E5%89%8A%E9%99%A4">四. ツイート削除</a></h4> <p>ノーコメント</p> <h4 id="五. 非同期処理"><a href="#%E4%BA%94.+%E9%9D%9E%E5%90%8C%E6%9C%9F%E5%87%A6%E7%90%86">五. 非同期処理</a></h4> <p>アップロードされてそのままツイートの削除を行うと、画面がタイムアウトしてしまいます。<br /> そのため削除処理はLaravelのキューを使って非同期にしています。<br /> 失敗時の再実行もできるようになるので便利ですね。</p> <h4 id="六. メール送信"><a href="#%E5%85%AD.+%E3%83%A1%E3%83%BC%E3%83%AB%E9%80%81%E4%BF%A1">六. メール送信</a></h4> <p>必ずユーザーに到達するように<a target="_blank" rel="nofollow noopener" href="https://sendgrid.kke.co.jp/">SendGrid</a>を使っています。<br /> 返信や問い合わせを受けるためにはメールサーバーの設定が必要なので注意してください。<br /> サーバーが用意できない場合は、G Suiteなどのホスティングサービスを利用しましょう。</p> <h4 id="七. ログ出力 + Slack通知"><a href="#%E4%B8%83.+%E3%83%AD%E3%82%B0%E5%87%BA%E5%8A%9B+%2B+Slack%E9%80%9A%E7%9F%A5">七. ログ出力 + Slack通知</a></h4> <p>本番での例外発生時にはSlackにスタックトレースを飛ばすようにしています。<br /> 他にも、ツイート削除処理成功時など、正常系でも重要なものはSlackに通知を飛ばしてます。</p> <p>ログは、出せる項目をなるべく出すようにしています。<br /> Laravelのログ出力について記事書いてるので興味あったら読んでください↓<br /> <a target="_blank" rel="nofollow noopener" href="https://qiita.com/_hiro_dev/items/cea556897a36fcec31bf">【Laravel】ログのフォーマットを変更してIPアドレスやユーザー名などを出力する</a></p> <h3 id="2. リリース準備"><a href="#2.+%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E6%BA%96%E5%82%99">2. リリース準備</a></h3> <h4 id="一. LP(トップページ)作成"><a href="#%E4%B8%80.+LP%28%E3%83%88%E3%83%83%E3%83%97%E3%83%9A%E3%83%BC%E3%82%B8%29%E4%BD%9C%E6%88%90">一. LP(トップページ)作成</a></h4> <p>ユーザーに効果的に訴求できる文言を考える必要があります。<br /> デザイナーの人は腕の見せどころだと思います。<br /> 文字や画像・アニメーションを使っていい感じのレイアウトにしましょう。</p> <p><a target="_blank" rel="nofollow noopener" href="https://peraichi.com/">ペライチ</a>などのツールを使っても良いと思います。<br /> コンバージョンに直結するので、一番力を入れるべき部分です。外注も考えましょう。</p> <p>ツイ消し職人のようなツール系のサービスの場合は、そんなに凝らなくても結構コンバージョンします。</p> <h4 id="二. 利用規約・プライバシーポリシーの制定"><a href="#%E4%BA%8C.+%E5%88%A9%E7%94%A8%E8%A6%8F%E7%B4%84%E3%83%BB%E3%83%97%E3%83%A9%E3%82%A4%E3%83%90%E3%82%B7%E3%83%BC%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC%E3%81%AE%E5%88%B6%E5%AE%9A">二. 利用規約・プライバシーポリシーの制定</a></h4> <p><a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/gp/product/B07Q721691">この本</a>が大変参考になりました。コピペできるひな形データも付いてくるのでオススメです。</p> <h4 id="三. ☆特定商取引法に基づく表示の作成"><a href="#%E4%B8%89.+%E2%98%86%E7%89%B9%E5%AE%9A%E5%95%86%E5%8F%96%E5%BC%95%E6%B3%95%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%8F%E8%A1%A8%E7%A4%BA%E3%81%AE%E4%BD%9C%E6%88%90">三. ☆特定商取引法に基づく表示の作成</a></h4> <p>同上。<br /> 有料サービスの場合は必須です。<br /> 本名や住所、電話番号を晒さないといけないので、ここが一番の難関ではないでしょうか。<br /> 私の場合、IP電話アプリ(SMARTalk)を使い050から始まる電話番号を載せています。</p> <h4 id="四. Googleアナリティクス・Search Console設定"><a href="#%E5%9B%9B.+Google%E3%82%A2%E3%83%8A%E3%83%AA%E3%83%86%E3%82%A3%E3%82%AF%E3%82%B9%E3%83%BBSearch+Console%E8%A8%AD%E5%AE%9A">四. Googleアナリティクス・Search Console設定</a></h4> <p>ノーコメント</p> <h4 id="五. meta description設定"><a href="#%E4%BA%94.+meta+description%E8%A8%AD%E5%AE%9A">五. meta description設定</a></h4> <p>Googleの検索結果でタイトルとともに出るやつです。<br /> meta keywordは不要です。</p> <h4 id="六. ファビコン設定"><a href="#%E5%85%AD.+%E3%83%95%E3%82%A1%E3%83%93%E3%82%B3%E3%83%B3%E8%A8%AD%E5%AE%9A">六. ファビコン設定</a></h4> <p>GIMPで作りました。<br /> サービスのロゴがある場合はファビコンにも活かせます。</p> <h4 id="七. OGP設定"><a href="#%E4%B8%83.+OGP%E8%A8%AD%E5%AE%9A">七. OGP設定</a></h4> <p>GIMPで作りました。<br /> OGP画像を動的に生成するサービスでは、トップページ用の画像を同じ方法で作るのも良いかも。<br /> CTRに直結するので、ここも外注を検討しましょう。</p> <h4 id="八. サイトマップ設定"><a href="#%E5%85%AB.+%E3%82%B5%E3%82%A4%E3%83%88%E3%83%9E%E3%83%83%E3%83%97%E8%A8%AD%E5%AE%9A">八. サイトマップ設定</a></h4> <p>Search Consoleで送信します。<br /> <a target="_blank" rel="nofollow noopener" href="http://www.sitemapxml.jp/">sitemap.xml Editor</a>を使うと簡単に作成できます。<br /> サイトが新しく、外部からのリンクが少ない場合はあったほうが良いみたいです。</p> <h4 id="九. SNSシェアボタンの設置"><a href="#%E4%B9%9D.+SNS%E3%82%B7%E3%82%A7%E3%82%A2%E3%83%9C%E3%82%BF%E3%83%B3%E3%81%AE%E8%A8%AD%E7%BD%AE">九. SNSシェアボタンの設置</a></h4> <p>↓こういうのです。<br /> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117180/71ddf9f6-9556-80d9-1554-2d0fb875a11e.png" alt="ツイ消し職人 - twikeshi.net.png" /><br /> ユーザーに拡散してもらえる仕組みを作っておくことは重要です。</p> <h4 id="十. お問い合わせフォームの設置"><a href="#%E5%8D%81.+%E3%81%8A%E5%95%8F%E3%81%84%E5%90%88%E3%82%8F%E3%81%9B%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE%E8%A8%AD%E7%BD%AE">十. お問い合わせフォームの設置</a></h4> <p>自分で作るのがめんどくさい場合は、<a target="_blank" rel="nofollow noopener" href="https://www.google.com/intl/ja_jp/forms/about/">Googleフォーム</a>や<a target="_blank" rel="nofollow noopener" href="https://form.run/ja">formrun</a>などを活用しましょう。<br /> お問い合わせフォームの代わりに、チャットサポートツールを入れるのもオススメです。</p> <h3 id="3. リリース"><a href="#3.+%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9">3. リリース</a></h3> <h4 id="一. デプロイ"><a href="#%E4%B8%80.+%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4">一. デプロイ</a></h4> <p>Laravel + レンタルサーバーの場合はgit pullすればほぼ終わりです。<br /> あとは.env書いてマイグレーションしてキャッシュ系のコマンドを叩くだけです。<br /> もちろん、GitHub ActionsなどのCIを設定するのも良いと思います。</p> <p>私の場合は、以下のようなデプロイスクリプトを用意しています。</p> <pre><code>#!/bin/sh git pull composer install --optimize-autoloader --no-dev php artisan config:cache php artisan view:cache php artisan route:cache </code></pre> <h4 id="二. テスト"><a href="#%E4%BA%8C.+%E3%83%86%E3%82%B9%E3%83%88">二. テスト</a></h4> <p>本番環境で全ての機能がうまく動くことを確認しました。<br /> 中規模〜大規模サービスの場合は、検証環境の用意とテスト自動化がされていないと運用がしんどくなります。</p> <h2 id="八. リリース後"><a href="#%E5%85%AB.+%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E5%BE%8C">八. リリース後</a></h2> <h3 id="1. 知り合い・友人への拡散"><a href="#1.+%E7%9F%A5%E3%82%8A%E5%90%88%E3%81%84%E3%83%BB%E5%8F%8B%E4%BA%BA%E3%81%B8%E3%81%AE%E6%8B%A1%E6%95%A3">1. 知り合い・友人への拡散</a></h3> <p>LINE, Twitter, Facebookなどで拡散して使ってもらいましょう。</p> <h3 id="2. プレスリリースを出す"><a href="#2.+%E3%83%97%E3%83%AC%E3%82%B9%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%82%92%E5%87%BA%E3%81%99">2. プレスリリースを出す</a></h3> <p>お金があれば<a target="_blank" rel="nofollow noopener" href="https://prtimes.jp/">PR TIMES</a>などの有名サイトに出すのがオススメです。<br /> (もしくは、法人なら<a target="_blank" rel="nofollow noopener" href="https://prtimes.jp/startup_free/">スタートアップチャレンジ</a>の条件を満たすと無料になります)</p> <p>私はお金がなかったので、<a target="_blank" rel="nofollow noopener" href="https://www.value-press.com/">valuepress</a>のフリープランで配信しました。<br /> 配信は無料ですが、プレスリリースの内容を修正する場合はお金がかかるので気を付けましょう。<br /> <a target="_blank" rel="nofollow noopener" href="https://www.value-press.com/pressrelease/241519">3,200件を超えるツイートを一括削除できるツイ消しサービス「ツイ消し職人」を提供開始</a></p> <h3 id="3. アプリ紹介サイトに登録"><a href="#3.+%E3%82%A2%E3%83%97%E3%83%AA%E7%B4%B9%E4%BB%8B%E3%82%B5%E3%82%A4%E3%83%88%E3%81%AB%E7%99%BB%E9%8C%B2">3. アプリ紹介サイトに登録</a></h3> <p>私の場合、<a target="_blank" rel="nofollow noopener" href="https://anymake.app/">AnyMake</a>や<a target="_blank" rel="nofollow noopener" href="https://www.makepost.net/">makepost</a>、<a target="_blank" rel="nofollow noopener" href="https://www.eggineer.com/">Eggineer</a>、<a target="_blank" rel="nofollow noopener" href="https://applishow.com/">Applishow</a>を活用しています。</p> <h3 id="4. 新聞の広告枠に出稿する"><a href="#4.+%E6%96%B0%E8%81%9E%E3%81%AE%E5%BA%83%E5%91%8A%E6%9E%A0%E3%81%AB%E5%87%BA%E7%A8%BF%E3%81%99%E3%82%8B">4. 新聞の広告枠に出稿する</a></h3> <p>リリース直後にスポーツ新聞の方から電話があり、新聞とサイトに広告を載せないかと打診がありました。<br /> 条件が合わなかったためお断りしましたが、人によっては選択肢になり得ると思います。</p> <h3 id="5. アフィリエイト広告に出稿する"><a href="#5.+%E3%82%A2%E3%83%95%E3%82%A3%E3%83%AA%E3%82%A8%E3%82%A4%E3%83%88%E5%BA%83%E5%91%8A%E3%81%AB%E5%87%BA%E7%A8%BF%E3%81%99%E3%82%8B">5. アフィリエイト広告に出稿する</a></h3> <p>検討しましたが、結局使いませんでした。<br /> お金がある場合は、<a target="_blank" rel="nofollow noopener" href="https://www.a8.net/">A8.net</a>などの大手ASPを使うのが良いと思います。<br /> <a target="_blank" rel="nofollow noopener" href="https://www.monetrack.com/">マネートラック</a>ならば初期費用0円・月額費用0円で始められるようです。</p> <h3 id="6. SNS広告に出稿する"><a href="#6.+SNS%E5%BA%83%E5%91%8A%E3%81%AB%E5%87%BA%E7%A8%BF%E3%81%99%E3%82%8B">6. SNS広告に出稿する</a></h3> <p>以前利用していました。<br /> 私の場合はTwitterユーザーをターゲットにしたサービスなので、Twitter広告と相性が良いです。<br /> 月予算は安めでもかなりコンバージョンに繋がったので、広告費は普通に回収できています。</p> <h3 id="7. リスティング広告に出稿する"><a href="#7.+%E3%83%AA%E3%82%B9%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E5%BA%83%E5%91%8A%E3%81%AB%E5%87%BA%E7%A8%BF%E3%81%99%E3%82%8B">7. リスティング広告に出稿する</a></h3> <p>以前利用していました。<br /> Twitter広告よりも予算が必要で効果が薄かったため、すぐにやめました。</p> <h3 id="8. 保守開発"><a href="#8.+%E4%BF%9D%E5%AE%88%E9%96%8B%E7%99%BA">8. 保守開発</a></h3> <p>本番環境でのエラーを監視し、新しく発現したバグがあれば修正しましょう。<br /> 手元で再現しないエラーは...ユーザー問い合わせを待つしか無い。。</p> <p>もちろん、機能追加などサービス改善のための開発は怠らないようにしましょう。<br /> 大幅リニューアルや作り直しなどの選択肢もあります。</p> <h3 id="9. ブログなどでの発信"><a href="#9.+%E3%83%96%E3%83%AD%E3%82%B0%E3%81%AA%E3%81%A9%E3%81%A7%E3%81%AE%E7%99%BA%E4%BF%A1">9. ブログなどでの発信</a></h3> <p>この記事のことですね。<br /> Qiita, Crieit, Zenn, Note, ブログなどの選択肢があります。<br /> サービスを知ってもらうだけでなく、転職活動などでも役に立ちます。</p> <p>Noteに記事を投稿しているのでこちらも参考にしてください。<br /> <a target="_blank" rel="nofollow noopener" href="https://note.com/_hiro_dev/n/n3332c056a65a">たった2週間で作ったWebサービスで月11万円の売上を達成した話</a></p> ひろ⚡個人開発 tag:crieit.net,2005:PublicArticle/15867 2020-04-24T21:08:44+09:00 2020-04-24T21:08:44+09:00 https://crieit.net/posts/9fd7f88e5665ff21a052847b67df7d0d 完全匿名型討論サービス【みくぽん】を開発&公開しました <h1 id="10日で匿名型討論Webサービスを公開しました"><a href="#10%E6%97%A5%E3%81%A7%E5%8C%BF%E5%90%8D%E5%9E%8B%E8%A8%8E%E8%AB%96Web%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E5%85%AC%E9%96%8B%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F">10日で匿名型討論Webサービスを公開しました</a></h1> <p>企画から始まり、設計、デザイン、コーディングまでを10日間で行い、匿名型討論サービス【みくぽん】を作成しました。<br /> こちらのリンクから遊べます。試してみてください<br /> <a target="_blank" rel="nofollow noopener" href="https://mixpon.net/">みくぽん</a></p> <h3 id="【議題】"><a href="#%E3%80%90%E8%AD%B0%E9%A1%8C%E3%80%91">【議題】</a></h3> <p>3年後も仕事で使えそうなプログラミング言語は?</p> <p><code>JavaScript or Python</code></p> <p><a target="_blank" rel="nofollow noopener" href="https://mixpon.net/topic/553">回答はこちらから</a></p> <h2 id="使った技術"><a href="#%E4%BD%BF%E3%81%A3%E3%81%9F%E6%8A%80%E8%A1%93">使った技術</a></h2> <ol> <li>Laravel</li> <li>MySQL</li> <li>Heroku</li> <li>Xサーバー</li> <li>AWS S3</li> </ol> <h3 id="Laravel"><a href="#Laravel">Laravel</a></h3> <p>プログラミング言語にはPHP、フレームワークにLaravelを使用しました。<br /> 質問箱を始めとする、質問サービス同様画像加工をし、OGPに設定するようにしています。<br /> データベースにはMySQLを使用しています。</p> <h3 id="Heroku"><a href="#Heroku">Heroku</a></h3> <p>テスト環境構築用に無料で公開できるHerokuを採用しました。<br /> こちらを使い、β版のリリースを実施し、知人にテストプレイを依頼しました。<br /> 公開前のテストに使うには十分なサービスです。(本番リリースも表示速度等気にしないのであれば使用は可能かと思います)</p> <h3 id="Xサーバー"><a href="#X%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC">Xサーバー</a></h3> <p>本番リリースには普段私の<a target="_blank" rel="nofollow noopener" href="https://yone-lab.com/">ブログ</a>を置いているXサーバーを使用しました。<br /> 最も安いプランでも50個のデータベースが作成でき最高ですね。表示速度も申し分ありません。</p> <h3 id="AWS S3"><a href="#AWS+S3">AWS S3</a></h3> <p>ユーザーが投稿時に生成される画像を格納するために使用しました。<br /> 1年間の無料期間で使用しています。</p> <p>以上まとめると、運用にかかる費用はドメインとサーバー契約費だけになります。</p> <h3 id="サービスをリリースしてみての感想"><a href="#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%81%97%E3%81%A6%E3%81%BF%E3%81%A6%E3%81%AE%E6%84%9F%E6%83%B3">サービスをリリースしてみての感想</a></h3> <p>いろんな開発者のブログなどから伺っていたとおり、個人サービスは公開=終了ではなく、<br /> 公開=スタートをきった というのを実感しています。<br /> 今ではどうやったらこのサービスをみんなが使ってくれるのかを考える毎日です。</p> <p>意見の投稿だけであれば、アカウント作成は不要です。<br /> ぜひ皆さん意見を投稿してみてください</p> よね@みくぽん公開中 tag:crieit.net,2005:PublicArticle/15826 2020-04-14T13:52:22+09:00 2020-04-14T13:52:22+09:00 https://crieit.net/posts/Google 独学初心者がGoogle風の書籍検索サービスを作ってみた【個人開発】 <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436810/670938fb-e2c7-aed0-1def-f1c2cce69233.png" alt="GeekleDesktop.png" /><br /> 独学でプログラミングを学習しています。<br /> 「作りながら学ぶのがいい」ということでGoogle風の技術書検索サービスを開発しました。</p> <p>アイデア的に似ているサービスはありますが、自分が欲しいものとは少し違っていたので作りました。</p> <p>初学者なりに試行錯誤したので、アプリの仕組みや作った方法をまとめます。</p> <p>プログラミング学習中の人や個人開発を考えている人のモチベUPに貢献できたらいいなと思います。</p> <h1 id="作ったサービス「技術書検索サービス」"><a href="#%E4%BD%9C%E3%81%A3%E3%81%9F%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%80%8C%E6%8A%80%E8%A1%93%E6%9B%B8%E6%A4%9C%E7%B4%A2%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%80%8D">作ったサービス「技術書検索サービス」</a></h1> <p>作ったのは「Geekle(ギークル)」という技術書検索サービス。</p> <p>-> <a target="_blank" rel="nofollow noopener" href="https://geekle.jp/"> Geekle(ギークル) | 技術書検索サービス</a><br /> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436810/b77cdf01-e3c8-f3b4-6440-37640986c44e.png" alt="Geekle___エンジニア向けの技術書検索サイト.png" /></p> <h3 id="サービス概要"><a href="#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E6%A6%82%E8%A6%81">サービス概要</a></h3> <p>Geekleは、<strong>評価の高い技術書を検索できる</strong>サービスです。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436810/c8b9a26b-86c0-4e4e-5a82-016182b53434.png" alt="Geekle全体.png" /></p> <p>例えば、「Pythonを勉強したい!どの書籍がいんだろうか!」ってなったときに「Python」というキーワード(キーワードはQiitaのタグにあるものに限定されます:サジェストで表示される)で検索すると、</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436810/f118bf6b-2d83-42d6-8bc2-74f776c50a79.png" alt="Geekle___エンジニア向けの技術書検索サイト.png" /></p> <p>その技術キーワードに対する「評価の高い書籍リスト」が検索結果として表示されます。検索結果の並びはQiitaでの言及記事数をはじめ、複数の要素から総合的に算出。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436810/4954cc89-6397-45c6-840e-d513cb7ea4e1.png" alt="Pythonのおすすめ本568冊___Geekle.png" /></p> <p>学びたい技術がある時に購入候補となる書籍を絞り込むのに使えます!</p> <h2 id="開発の動機"><a href="#%E9%96%8B%E7%99%BA%E3%81%AE%E5%8B%95%E6%A9%9F">開発の動機</a></h2> <p>プログラミングを学習する中で、たくさんの書籍を購入してきました。</p> <p>そのときに候補となる本をピックアップして、一つずつ評判を確認し、本屋で立ち読みして買ってたので、「○○という技術を学ぼう→その技術の評判の良い技術書がすぐわかるサービスがあったらなー」と思っていました。</p> <p>Qiita上の書籍情報を見られるサービスはすでにいくつもありますが、既存のモノは「Qiita上の書籍情報を可視化すると面白い」というコンセプトであるため、キーワード(タグ)に対して関連性が薄い書籍も多く表示される仕様となっていました(それが書籍との偶発的な出会いになって面白いというコンセプト)。</p> <p>自分の希望は「今、学ぶのに適した書籍の候補」をストレートに見つけられるサービスだったので、関連性の薄い書籍はない方がよかったし、なるべく情報が新しい評価の高い書籍が表示されて欲しかった。</p> <p>そこで、自分の希望を実現したモノを作ってみました。</p> <h2 id="どう作ったか"><a href="#%E3%81%A9%E3%81%86%E4%BD%9C%E3%81%A3%E3%81%9F%E3%81%8B">どう作ったか</a></h2> <p>使った技術とか</p> <ul> <li>アプリ:Laravel + Vue.js</li> <li>バッチ(DB作成):生PHP</li> <li>インフラ:AWS(EC2・RDS・Rout53・ALB)</li> <li>制作期間:4ヶ月ちょっと</li> </ul> <p>裏側の仕組みをどう作ったのか解説します。</p> <p>自分なりに色々と考えて作りましたが、独学初心者なので生暖かく読んでください...。あと、「もっとこうすればいいのに!」とかあればアドバイスして頂けると嬉しいです。</p> <h3 id="書籍DBについて"><a href="#%E6%9B%B8%E7%B1%8DDB%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">書籍DBについて</a></h3> <p>書籍のDBは、QiitaのAPIで記事データを取得して、書籍へのリンクらしきURLを解析し、そこから書籍の識別番号(ISBN・ASIN)を抽出後、番号を使ってopneBDやGoogleBookApiなどで書籍データを取得して構築しています。</p> <p>これらの方法は</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/jabba/items/edefda09121877b79760">技術書ランキングサイトをQiita記事の集計から作ったら、約4000冊の技術本がいい感じに並んだ</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/Yuhsak/items/03967437b8a6438eb625">【個人開発】 技術書籍のレビューや「読みたい」を記録するサービスを作った</a></li> </ul> <p>の記事を参考にさせていただきました。</p> <p>独学の自分がサービス開発できたのはこういったノウハウが公開・共有されていたからです。先人の皆様ありがとうございます。僕もこの記事でやったことを共有します( ̄^ ̄)ゞ</p> <h3 id="書籍の順位付けを工夫"><a href="#%E6%9B%B8%E7%B1%8D%E3%81%AE%E9%A0%86%E4%BD%8D%E4%BB%98%E3%81%91%E3%82%92%E5%B7%A5%E5%A4%AB">書籍の順位付けを工夫</a></h3> <p>Qiitaの記事についているタグをそのまま書籍のタグとして、Qiitaで言及されている記事数をカウントすることでタグごとに書籍の順位づけを行っています。</p> <p>しかし、Qiitaの記事数のみで順位付けを行うと、普遍的な名著(リーダブルコードなど)が多くのタグで上位を独占してしまるというデメリットがありました。</p> <p>検索ワードが「PHP」でも「Ruby」でもリーダブルコードが一番上になってしまう。</p> <p>また、出版から時間が経過している書籍の方が言及される記事数が多く、新しい書籍は言及される記事数が少ないため、新しい良本が上位に表示できなかったり、PHPとLaravelのように「言語」と「フレームワーク」の検索結果がほぼ同じになるという問題点がありました。</p> <p>僕が作りたいのは「学習したい技術ごとに今選ぶべき良書がわかるサービス」だったため、なるべく情報の新しい良本が上位表示されて欲しいし、PHPなら生PHPの書籍が上位、LaravelならLaravelの書籍が上位という結果になって欲しかった。</p> <p>そこで、Qiitaの記事数に加えて</p> <p>・検索ワード(タグ)の文字が書籍のタイトルに含まれる場合はプラス点<br /> ・出版日時が古くなればなるほどマイナス点</p> <p>などを加えて傾斜配点をかける事で検索結果を調整しています。</p> <p>試行錯誤の結果、悪くない結果がでるようになりました。<br /> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436810/f5a9e246-bae2-76ae-62b9-a4f90cec3403.png" alt="PHPLaravel.png" /><br /> (言語とフレームワークも異なる検索結果になってる)</p> <p>今後も改良して精度を上げていきます。</p> <h3 id="デザインとか"><a href="#%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%81%A8%E3%81%8B">デザインとか</a></h3> <p>デザインは、最初にカラー(紫・黒・白)を決めました。</p> <p>柱となる色は紫をにしたのは、「プログラミングって現在の魔法っぽい→魔法は紫っぽい」という発想から。技術書を読んで勉強することを魔法を学んでる感じだと捉えると学習が楽しくなる気がします(中二心)。</p> <p>レイアウトは、たくさんのサービスを並べて特徴を抽象化し、取り入れていくというやり方で考えました。</p> <p>具体的に説明すると、書籍検索サービスは画像付きでコンテンツを表示するサービスになるよね→Amazonプライムビデオやネットフリックスなど画像付きでコンテンツを大量に並べてる有名サイトをいくつもみる→あ、横並びにしてスライドするUIがデフォルトっぽいなー(これが抽象化)→自分のサービスに取り入れるという流れ。</p> <p>「基本となっている型を探す」という感じ。</p> <h3 id="今後の改良/グロース"><a href="#%E4%BB%8A%E5%BE%8C%E3%81%AE%E6%94%B9%E8%89%AF%2F%E3%82%B0%E3%83%AD%E3%83%BC%E3%82%B9">今後の改良/グロース</a></h3> <p>やりたいことはたくさんあります。</p> <p>・SEOに強い構成にする<br /> ・SPA化<br /> ・レビューを集める仕組み構築<br /> ・技術書のセール情報の掲載</p> <p>などなど。自分の技術力向上やサービスグロースの実験の場としても使っていきたい。</p> <h3 id="振り返り"><a href="#%E6%8C%AF%E3%82%8A%E8%BF%94%E3%82%8A">振り返り</a></h3> <p>当初、2ヶ月くらいで作れるだろうと思っていたのですが、DBを作るのに時間がかかってしまい、想定の倍以上の時間がかかってしまいました。</p> <p>開発中はわからないことだらけで苦しい時もりましたが、やっぱりプログラミングは楽しいですね!今回のアプリ開発を通してエンジニアになりたいという気持ちがより強くなりました。</p> <p>もっともっと勉強して色々なアプリ作っていきたいです。</p> <p>ここまで読んでくれた方ありがとうございます!<br /> ぜひ試しに使ってみてください(≧∀≦)</p> <p><a target="_blank" rel="nofollow noopener" href="https://geekle.jp/">Geekle(ギークル) | 技術書検索サービス</a></p> Jin tag:crieit.net,2005:PublicArticle/15756 2020-03-10T15:03:04+09:00 2020-03-10T15:03:04+09:00 https://crieit.net/posts/Laravel-WHERE LaravelのサブクエリでWHEREしたい時 <p>Laravelのwhereにサブクエリを使いたい時。パフォーマンスとかの話は置いておいて、ちょっと面白かったというか、なんだそれという感じなので。Laravel6。</p> <pre><code class="php">$sub = DB::raw('SELECT status FROM users WHERE id = posts.user_id'); $query->where($sub, $status); </code></pre> <p>上のだとなんか途中のテキスト解析中にエラーになる。正解は下で、全体をカッコで囲むだけ。</p> <pre><code class="php">$sub = DB::raw('(SELECT status FROM users WHERE id = posts.user_id)'); $query->where($sub, $status); </code></pre> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15743 2020-03-02T17:00:28+09:00 2020-03-02T17:00:28+09:00 https://crieit.net/posts/return-json-when-validation-of-form-request-fails FormRequestのバリデーション失敗時にjsonを返す <p>以下どちらかの実装でjsonレスポンスにできる。</p> <ul> <li><code>failedValidation()</code>をオーバーライドする</li> <li>ヘッダーに<code>Accept</code>または<code>X-Requested-With</code>を追加する</li> </ul> <p>Laravelのバージョンは6.15.0です。</p> <h2><code>failedValidation()</code>のオーバーライド</h2> <p>フォームリクエストクラスの<code>failedValidation()</code>をオーバーライドすることでjsonレスポンスかつメッセージをカスタマイズすることも可能。以下はサインアップのエンドポイントを想定したリクエストの例。</p> <pre><code class="php"><?php namespace App\Http\Requests; use Illuminate\Contracts\Validation\Validator; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Http\Exceptions\HttpResponseException; class SignUpRequest extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'user_id' => 'required', 'password' => 'required' ]; } public function messages() { return [ 'user_id.required' => 'ユーザーIDは必須です。', 'password.required' => 'パスワードは必須です。', ]; } protected function failedValidation(Validator $validator) { throw new HttpResponseException( response()->json([ 'message' => $validator->errors()->toArray(), ], 403) ); } } </code></pre> <h2>ヘッダーに<code>Accept</code>または<code>X-Requested-With</code>を追加する</h2> <p>エクセプションハンドラを変更していない場合、バリデーションエラー発生時は<code>Illuminate/Foundation/Exceptions/Handler::render()</code>でレスポンス生成が行われる。</p> <pre><code class="php"> // Illuminate/Foundation/Exceptions/Handler.php public function render($request, Exception $e) { if (method_exists($e, 'render') && $response = $e->render($request)) { return Router::toResponse($request, $response); } elseif ($e instanceof Responsable) { return $e->toResponse($request); } $e = $this->prepareException($e); if ($e instanceof HttpResponseException) { return $e->getResponse(); } elseif ($e instanceof AuthenticationException) { return $this->unauthenticated($request, $e); } elseif ($e instanceof ValidationException) { return $this->convertValidationExceptionToResponse($e, $request); } return $request->expectsJson() ? $this->prepareJsonResponse($request, $e) : $this->prepareResponse($request, $e); } </code></pre> <p>今回はバリデーションエラーの場合なので<code>convertValidationExceptionToResponse()</code>が実行される。</p> <pre><code class="php"> // Illuminate/Foundation/Exceptions/Handler.php protected function convertValidationExceptionToResponse(ValidationException $e, $request) { if ($e->response) { return $e->response; } return $request->expectsJson() ? $this->invalidJson($request, $e) : $this->invalid($request, $e); } </code></pre> <p><code>expectsJson()</code>はヘッダに<code>X-Requested-With: XMLHttpRequest</code>が含まれているか、ヘッダに<code>Accept: .../json</code>もしくは<code>Accept: ...+json</code>が含まれている場合にjsonレスポンスを返却する。</p> <p>そのためミドルウェアでヘッダを追加することでjsonレスポンスが取得できる。</p> <pre><code class="php"><?php // app/Http/Middleware/EnforceJson.php namespace App\Http\Middleware; use Closure; /** * @see https://stackoverflow.com/questions/44453221/how-to-set-header-for-all-requests-in-route-group */ class EnforceJson { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $request->headers->set('Accept', 'application/json'); return $next($request); } } </code></pre> <pre><code class="php"><?php // app/Http/Kernel.php namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; class Kernel extends HttpKernel { // ... protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ 'throttle:60,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, \App\Http\Middleware\EnforceJson::class, // 追加 ], ]; // ... } </code></pre> <p>個人的には返却するメッセージを変更できるので<code>failedValidation()</code>をオーバーライドするほうが好みです。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/junsan50/items/ec7f810decd3b82d3d76">【Laravel5】FormRequestのバリデーション結果をJSON APIで返す - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/kd9951/items/9b6ef7d2c505522d873b">Laravel APIで常にJSONをリクエストするミドルウェア - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/44453221/how-to-set-header-for-all-requests-in-route-group">php - How to set header for all requests in route group - Stack Overflow</a></li> </ul> choco