- 投稿日:2020-03-27T21:50:23+09:00
30代未経験からポートフォリオ作り、実務経験を積みGo転職までに実践したこと
はじめに
- 私は、全くの未経験で、働きながら独学4ヶ月程度でポートフォリオ(Laravel)を作り、Web系自社開発企業に転職することができました。 そして、8ヶ月の実務経験(主にLaravel,Vue.js)を積み、ポートフォリオ(Go)を作り、Go/AWS等を使用されている会社さんから内定を頂きました。
- 未経験からWeb系自社開発企業を目指している方に向けて、経験を踏まえて記事を書いてみました。
- あくまで一つの例ですので、いろんな方の経験談を踏まえて総合的に判断されるといいと思います。
記事の流れ
- 未経験からポートフォリオを作り、Laravel案件参画まで
- 実践した勉強方法
- 使って良かった教材
- ポートフォリオ作り
- 実務を経験して
- Goのポートフォリオを作り、内定を得るまで
1. 未経験からポートフォリオを作り、Laravel案件参画まで
1ヶ月目
- 何か新しいことを始めたいと思って色々検索した時に、たどり着いたのが、ドットインストール、Progateというサイトでした。
- 最初に、h1タグで、Hello Worldを挟んでブラウザに表示させた時の感動は、今でも忘れません。 プログラミングは、ゲームのように楽しくて、PS4のボタン多めバージョンだと思いました。
2ヶ月目
- ドットインストール、Progate、Paizeの有料会員になり、取り憑かれたようにプログラミングにハマってしまいました。(学習した順序は、HTML→ CSS→ Javascript→ PHP→ Laravel)
- この頃に、本格的にエンジニアへの転職を考え始めました。こんなに楽しいなら、職にしてしまおうと。
- 色々検索したところ、一つの言語・フレームワークで、ある程度のレベルのポートフォリオを作れば、30代未経験でもなんとかなるんじゃないかという仮説に至りました。
- その時、一番やっていたPHP(Laravel)に絞って、ポートフォリオを作り始めました。
3ヶ月目(主にポートフォリオ作り)
- Heroku、AWS(EC2)へのリリースや、Dockerによる環境構築にチャレンジしてみました。
- コンピュータの基礎を何も理解していなかったため、検索して見つけた記事の通りやってみて、途中で何時間もハマるということを繰り返していました。
- この時に、遅ればせながら、コンピュータの基礎、データベースの基礎、ネットワークの基礎、Linuxコマンド等を勉強しました。
- まだ見せれるポートフォリオがない段階で、数社の面談に行ってみましたが、反応は良くなかったです。言われて印象に残っている言葉としては、「PC持参で、作ったものを見せるぐらいじゃないとねー」と言われました。
4ヶ月目(主に転職)
- ポートフォリオの機能を追加しながら、転職活動をしました。
- 運よく、オンラインサロン内のslackの求人チャンネル経由で、転職が決まりました。(主にLaravelを使う求人検索サイトの新規開発フェーズ)
- 面談では、学歴や年齢は一切聞かれない代わりに、細かい部分までポートフォリオを見ていただき、とても嬉しかったことを覚えています。
- 転職が決まった時のポートフォリオのレベルは、会員登録機能、お気に入り機能、ダイレクトメッセージ機能、閲覧履歴機能、検索機能、マッチング機能等があって、インフラにAWSを使っていました。
- ただ、オンラインサロン内の求人チャンネル経由での転職は、現時点ではまだまだ数が少なく、再現性が低いと思います。WantedlyやGreenをおすすめします。
Railsではなく、Laravelを選んだ理由
現時点で、モダンなWeb系自社開発企業さんへの転職を目指す場合、言語のファーストチョイスは、案件数からして、Rudy(Rails)だと思います。ただ、セカンドチョイスとしてLaravelもいいと思います。
理由は、
- 未経験エンジニアのRailsポートフィリオのレベルは、どんどん上がってる
- Railsよりは少ないにしても、Laravelを使用する企業さんにも、モダンな環境はある
といったことです。
私は、Laravelを始めて1ヶ月程度で、Railsの方が案件が多いことを知りましたが、さっさと実務を経験した方がスキルアップが早いと判断し、そのままLaravelに絞りました。
もうすでに、Laravelの勉強を始めている方は、Railsに変えてなくても良いというのが私の見解です。2. 実践した勉強方法
1、 progate/ドットインストール/paiza
- プログラミングを始めるサイトとして定番になっています。無料でやってみて、分かりやすいと感じたサイトの有料会員になると良いと思います。私は、それぞれ2ヶ月間有料会員でした。
- 実務経験を積むと、この段階が物足りなくなり、飛ばして下の2に行くようになります。
2、 書籍かUdemyで学習(1周)
- 最初は、写経して動作を確かめていましたが、教材の言う通りにやるYesマンの状態にだんだん飽きてきて、もし教材の言うようにやらなかったらどうなるかという反抗心を持って取り組んでいました。
- 後で見返すことは何度もありますが、2周目はしないという方針でした。
- 暗記はせず、理解に努めました。具体的には、なんで?って思った部分を一つ一つ調べて、6割程度理解したら次に行くという感じでした。完璧主義は捨てた方が効率的です。
- Udemyは、月に何回かあるセールの時に千円台になるのでその時に買った方がいいと思います。
3、作ってみたい機能を自分でググりながら実装
この段階で一番成長できた実感があります。簡単な機能であっても、自分で検索しながら実装できたら、Progateでいうと、1200レベルぐらい上がります。(なので、Progateを何周もやることは非効率です。)
いきなり難易度の高い機能はやらず、できるだけ段差の低い階段をたくさん登っていくようにしていました。
何度も検索して、ブラウザがタブまみれになっても分からない場合は、いったん置いておいて、前提となっている知識の部分を書籍や動画で先にガッツリ勉強する(2と3を繰り返していく)というのを心がけていました。
「基礎」という言葉は、いろんな人がいろんな意味で使い、非常に曖昧な言葉ですが、「実務未経験者が、実務で初タスクに取り組むために必要な基礎」は、少なくとも1〜3まで終えたレベルであり、3で作った機能が多ければ多いほど、基礎が盤石になり、初タスクでの精神的負担が減ると思います。
作ってみたい機能が浮かばない場合は、Qiita内で、その言語・フレームワークで検索して、できそうな機能から実装してみるのも良いと思います。最初はQiitaのコピペであっても、少しずつ自分なりに付け加えて行き、たくさんの葉っぱを付ければ、いつの間にかオリジナルの綺麗な花が咲いています。
仮にうまく実装できなかったとしても、それは、できない方法を見つけたという意味でスキルアップしてますし、後で必ず役に立つので、落ち込まなくて良いと思います。
3.使って良かった教材
Laravel
- 青い本「PHPフレームワーク Laravel入門」
- 緑の本「PHPフレームワーク Laravel実践開発」
青い本と緑の本は、すごく分かりやすいですし、現場にも置いてあるので、Laravelをやるなら本当におすすめです。
青い本と緑の本を終えると、Laravelに関する調べ物の8割は、公式ドキュメントで解決できるようになりました。
公式ドキュメントは、どこに何が書いてあるか大まかに把握しておくだけでも、実務のタスクのスタートダッシュが違います。Git
- Udemy 「はじめてのGitとGitHub」(無料)
- Udemy 「もう怖くないGit!チーム開発で必要なGitを完全マスター」
Gitは勉強していないと、現場で一番迷惑をかけてしまう部分なので、優先度は高いと思います。
Linux
「Linux標準教科書」(PDFは無料)
AWSにデプロイする前に、一通りやっておくと理解が早いです。
Docker
※ 実務未経験時点では、Swarm、Kubernetes部分はやりませんでした。
AWS
リーダブルコード
他人から見て、より分かりやすいコード、機能を追加しやすいコードを書こうと考えた時に、ヒントになる本です。
4. ポートフォリオ作り
サイト: 相方マッチングサイト
ソースコード: GitHub
※検索部分やインフラ部分には、転職が決まった後に追加・変更した部分がありますポートフォリオとして何を作ったら良いか
- 基本的に作りたいものを作った方が良いです。その方が、ポートフォリオのモチベーションが継続しやすく、結果的にレベルの高い物が作れます。
- ただ、思い浮かばない人に対しては、マッチングサイトか、SNSをおすすめします。なぜなら、未経験者に作っている人が多いので、ネット上に情報も多く、また初学者に馴染みのある機能が多いからです。
- 私は、お笑いが好きなので、ボケとツッコミをマッチングさせることを思い付きました。そんなふうに、自分の好きなことを絡めた、マッチングサイトかSNSがおすすめです。
- 一方で、採用担当の方はおそらく、マッチングサイトやSNSを見ることにもう飽きていると考えられます。なので、マッチングサイトやSNS以外を作ればアピール材料にはなりますが、それを作っている人が少なければ少ないほど、情報も少なく、実装の難易度が上がるリスクもあります。その一長一短を認識した上で、選択した方が良いと思います。
ポートフォリオ作りで気を付けたこと
- 業務で忙しい採用担当の方が、ポートフォリオを見る負担をできるだけ減らすことをとにかく心がけました。
- 時間は限られるため、どこに力を入れるかが重要ですが、迷ったら、自分が一番面白そうだと感じたところに、熱意を爆発させて、それを採用担当者の目にとまる所に書くのが良いと思います。
ホーム画面で離脱されるかどうかが一つの山場
- ホーム画面のボタン群を見るだけで、どのような機能があるか把握できるようにしました。
- バッグエンドエンジニアのポートフォリオだとしても、採用担当者の離脱率を低下させるために、ホーム画面の見た目には気を使った方がいいとは思います。(私の場合は、見た目はBoostrapで済ませて、他の機能を一つでも増やす方針でした。)
簡単ログイン機能
- 採用担当の方が、わざわざメールアドレスやパスワードを入力してくれる可能性は低いので、ボタン一つでログインできるようにしました。
- ポートフォリオのURLを書く場合には、「簡単ログイン機能もあります」というような記載を添えてもいいと思います。
GitHubのReadmeをちゃんと書く。
- 採用担当の方に、必ず見てもらえる訳ではありませんが、見やすくしておくことで、離脱率を低下させることができると思います。そして、アピールしたい機能をReadmeのできるだけ上の方に書きました。
- 機能を追加するたびに、Readmeに追記することで、どんどんReadmeが充実してきてモチベーションにつながる面もありました。
5. 実務を経験して
- ポートフォリオを作っておいて本当に良かったと感じました。ポートフォリオでやったことが役に立つ場面ばかりで、ポートフォリオ作りの延長線上に実務があるということが身にしみてわかりました。
- ポートフォリオ作りのおかげで、少なくともLaravelに関しては、業務で精神的に苦労した記憶がありません。逆に、ポートフォリオで全く使わなかったVue.jsを業務で使う時は、非常に大変で、業務外でも必死に頑張った記憶があります。
- 実務を経験した上でポートフォリオを見ると、お恥ずかしいコードばかりで、誰にも見せたくなくなりました。逆に言うと、それだけ、実務経験には成長させる力があります。
エラーに動じなくなりました。
実務未経験時には、エラー画面は、おぞましい悪魔だと思っていましたが、実務経験を積むと、エラー原因のヒントをくれる天使に思えてきました。環境構築(→自分のスキルが上がったことを一番実感できるもの)
LaravelをAWS(EC2)へデプロイするのにかかった期間
期間 実務未経験時点 約1週間 実務3ヶ月 丸1日 実務6ヶ月 3時間程度 ※LaravelのEC2へのデプロイの手順は、以前にQiitaにまとめました。
LaravelをAWSのEC2へデプロイする手順6. Goのポートフォリオを作り、内定を得るまで
Goの学習
- Goを選んだ理由は、動的型付け(PHP)の次は、静的型付けも学んで、バッグエンドエンジニアとして対応できる技術の幅を広げたいと思ったからです。
- 勉強方法やポートフォリオ作りは、上記のLaravelの時とほぼ同じ方針で取り組みました。
- PHPやRubyに比べて、ネット上の情報が少ないので、他言語で培った考え方と検索力が必要になってきます。
- 実務で一つの言語・フレームワークに慣れると、他言語の習得も早いと聞いていましたが、本当にその通りでした。
使った教材
Go
Udemy 「現役シリコンバレーエンジニアが教えるGo入門」
後半のアプリ開発部分は、急に難しくなるので入門時点では後回しにしてもいいと思います。オライリーの書籍「Go言語によるWebアプリケーション開発」
チャットアプリ、コマンドラインツール、APIなど色々あるので、好きな部分からやってみて良いと思います。オライリーの書籍「Go言語による並行処理」
なかなかポートフォリオレベルで、並行処理が必要な処理はなく、ポートフォリオに組み込むことは難しかったです。GCP
ポートフォリオ
作成期間:3ヶ月程度
サイト: gortfolio
ソースコード:GitHub
- ブラックジャック、条文検索、チャット、スクレイピングなど、追加してみたい機能を自分勝手に詰め込んだサイトです。タイトルは、「Go」の「portfolio」で「gortfolio」としました。
- このポートフォリオを作る前は、バッグエンドにGinというGoフレームワークを使ったAPIとフロントエンドにVue.jsを使って別のアプリを作っていましたが、途中でGo自体に慣れ親しみたいと思い、フレームワークは使わず、Goのみで作りました。
- なるべくLaravelで作ったことないものを作りました。理由は、その方が新しいことを吸収できて楽しかったからです。
- Laravelという多機能なフレームワークに慣れていたせいで、苦労しましたが、フレームワークが裏側でやってくれている部分を自分で実装することで、また一つレベルアップできたと感じています。
- インフラは、LaravelのときはAWSを使っていたので、GoではGCP(GCE)を使ってみました。AWSでクラウドに慣れていれば、GCPの学習コストは低いです。
- ポートフォリオのレベルは決して高いものではありませんが、Laravelのポートフォリオと合わせて、自走能力や学習意欲が証明することはできたと感じています。
転職活動
- WantedlyやGreenを使い、いろんな会社さんの面談・面接を受けました。転職活動では、経験豊富なエンジニアや経営者の方とタダでお話ができるので、非常に有意義でした。
- Goのエンジニアを募集している会社さんのほとんどは、実務経験が豊富な人を求めているようでしたが、運よくGreen経由で内定を頂きました。
- 運が良かった部分があると思いますが、それでもその運を引き寄せたのは、ポートフォリオがあったからだと面接を通して感じました。
最後に
30代実務未経験であっても、Web系自社開発企業であっても、ポートフォリオという武器があれば、面接で十分に闘うことができます。
そして、ポートフォリオを自分で作った時の達成感は、作った人にしか味わえない最高の気持ち良さです。是非作ってみてください。
- 投稿日:2020-03-27T13:45:06+09:00
Laravelエラー:Argument 1 passed to App\Http\Controllers\GroupController::index() must be of the type int, string givenが出た時
TypeError Argument 1 passed to App\Http\Controllers\GroupController::index() must be of the type int, string givenこのエラーについて、同じエラーで困ってる方がいたら確認して欲しいポイントをお伝えしていきたいと思います。
web.phpのルーティング順序を疑ってみよう
前者がエラーが出ていた時のルーティングで、後者がエラーが消えた時のルーティングです。
書き順が違います。
本来は/groups/new
を呼び出したいアクションでもnew
を{id}
だと勘違いして、/groups/{id}
を呼んでしまっていたようです。laravelは仕様で上に書いてある設定を先に読み込んでしまいます。
もっとスマートな解放がlaravalには用意されていると思うのですが、今回は簡単に順序を入れ替えてエラー対処しました。web.php//前者 //グループ一覧表示 Route::get('/groups/{id}', 'GroupController@index')->name('groups.index'); //グループを新規作成ページを表示 Route::get('/groups/new', 'GroupController@new')->name('group.new'); //グループを新規作成 Route::post('/groups/new', 'GroupController@store');web.php//後者 //グループを新規作成ページを表示 Route::get('/groups/new', 'GroupController@new')->name('group.new'); //グループを新規作成 Route::post('/groups/new', 'GroupController@store'); //グループ一覧表示 Route::get('/groups/{id}', 'GroupController@index')->name('groups.index'); ///groups/{id}のルーティングを一番下に移動
- 投稿日:2020-03-27T12:28:07+09:00
さくらVPSにLaravelアプリケーションをデプロイする
環境
さくらVPS
CentOS 7
PHP 7.3.1
MySQL 5.6
Git 1.8.3.1
Composer 1.9.3
Bitbucketはじめに
Apache, PHP, phpMyAdmin, MySQL, Composer, Gitのインストールは終わっているものとします。
VirtualHostを使用しているため、他にもプロジェクトが複数ある中でのデプロイになります。手順
①sshでサーバーに接続。
②データベースを作成
phpMyAdminにログインしLaravelアプリケーション用のデータベースを作成する。
照合順序はutf8_general_ciで設定しました。③Laravelアプリケーションを設置。
# wwwに移動 cd /var/www # Laravelを設置するディレクトリを作る。 mkdir example cd example # Laravelをgit cloneで持ってくる。 ○○○の部分は自分のBitbucketの環境に合わせる。 # GitHubを使っている場合はGitHubのcloneコマンド打てばOKだと思います。 git clone git@bitbucket.org:○○○/example.git # クローンしたLaravelアプリケーションに移動しておく。 cd example④.envを作成する。【】内に変更。
cp .env.example .env vi .env # viコマンドで下記が出てくるので適宜変更していく APP_ENV=【production】 APP_URL=【アプリケーションのURL】 DB_CONNECTION=mysql DB_HOST=localhost DB_PORT=3306 DB_DATABASE=【データベース名】 DB_USERNAME=【データベースのユーザー名】 DB_PASSWORD=【パスワード】⑤Laravelセットアップ
php artisan key:generate⑥apacheの設定
# confファイルまで移動します。 cd /etc/httpd/conf.d/ # confファイルのバックアップを取っておきます。 cp vhost.conf vhost.conf_日付 # vhost.confの編集 vi vhost.conf # 以下を最下部に書く <VirtualHost *:80> DocumentRoot /var/www/example/【アプリケーション名】/public ServerName ○○○○○○○○○.com <Directory "/var/www/example/【アプリケーション名】/public"> #Options FollowSymLinks Options All AllowOverride All Require all granted </Directory> ErrorLog logs/【アプリケーション名】_error_log CustomLog logs/【アプリケーション名】_access_log </VirtualHost> # apacheの再起動 systemctl restart httpd⑦アプリケーションディレクトリまで移動しstorageとbootstrap/cacheを権限を変更する
chmod -R 775 example/【アプリケーション名】/storage chmod -R 775 example/【アプリケーション名】/bootstrap/cache⑧マイグレーションを行う
php artisan migrateあとは設定したドメインでアクセスして表示できればOKです。
- 投稿日:2020-03-27T10:47:35+09:00
Laravel + PHPUnitでパスセグメント(パスパラメーター)を再現する
ここのコードは実際には動作しないと思われます。
俺たちは雰囲気でコードを書いている。例えば以下のようにURLを設定します。
routes.phpRoute::get('/{user_id}', 'UserController@show'); Route::get('/{user_id}/edit', 'UserController@edit'); Route::get('/{user_id}/hoge', 'UserController@hoge'); Route::get('/{user_id}/fuga', 'UserController@fuga');ユーザーが存在しなければ例外とします。
必然的にUserクラスは1つしか存在してはいけないので、ServiceProviderでsingletonにします。AppServiceProvider.phppublic function boot() { $this->app->singleton(User::class, function() { return (app()->make(UserService::class)) ->findUser(); }); }UserService.phppublic function findUser() { $user = User::find(request()->route()->parameter('user_id')); if (is_null($user)) { throw new NotFoundException('ユーザーが見つかりません'); } return $user; }これでどのクラスからでも
app()->make(User::class)
でユーザー情報が取得できるようになりました。
なお、あくまで例としてUserクラスを挙げていますが、Laravelでは認証済みユーザーはAuth::user()
で取ってこれます。以下、本題のテストのお話です。
単にリクエストをテストするだけなら簡単です。
Feature/UserTest.php/** * @test */ public function ユーザーがいなければ404になること() { $response = $this->get('/should_404'); $response->assertStatus(404); }では
findUser
を単体テストするにはどうすれば良いでしょうか。
単純にfindUserメソッドを呼ぶと、request()->route()
の時点でnullが返ってくるため->parameter('user_id')
で例外になります。結論として、事前にRequestを疑似的に再現して対処します。
Unit/UserTest.php/** * @test */ public function 指定されたユーザーがいなければNotFoundExceptionになること() { $this->expectException(NotFoundException::class); request()->setRouteResolver(function () { return (new Route('POST', '/{user_id}', []))->bind( new Request([], [], [], [], [], ['REQUEST_URI' => '/should_not_found']) ); }); (app()->make(UserService::class))->findUser(); }参考:
Simulate a http request and parse route parameters in Laravel testcase
- 投稿日:2020-03-27T10:05:56+09:00
MySQL テーブルのカラムを出力しようとした時にエラーが出た話
目的
- laravelのマイグレーションファイルを使用してとあるテーブルにカラム追加したものを確認しようとしたらエラーが発生し解決した話をまとめる
実施環境
- ハードウェア環境
項目 情報 備考 OS macOS Catalina(10.15.3) ハードウェア MacBook Air (11-inch ,2012) プロセッサ 1.7 GHz デュアルコアIntel Core i5 メモリ 8 GB 1600 MHz DDR3 グラフィックス Intel HD Graphics 4000 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.3 Homwbrewを用いて導入 Laravel バージョン 7.0.8 commposerを用いて導入 MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いて導入 エラー内容
MySQLのコマンドラインにて下記のコマンドを実行したとこ「ERROR 1046 (3D000): No database selected」が出力された。
mysql> show columns from テーブル名;原因
- エラーメッセージにもある様にデータベース名を指定せずにテーブル名のみを指定したためエラーが発生している。
解決方法
- コマンド
how columns
の実行時にデータベース名も指定して実行する。MySQLのコマンドラインで
how columns
を実行する際の例を下記に記載する。mysql> how columns from データベース名.テーブル名
- 投稿日:2020-03-27T02:18:23+09:00
Laravelでresource使用してる時のroute()とかの一覧
Resource & route()
いつも書き方忘れてハマるので自分用に備忘録
Blade
index(一覧画面)
リンク
<a href="{{ route("user.index") }}">一覧画面へのリンク</a>create(作成画面)
リンク
<a href="{{ route("user.create") }}">作成画面へのリンク</a>store(作成処理)
form
<form action="{{ route("user.store") }}" action="post"> @csrfshow(詳細画面)
リンク
<a href="{{ route("user.show", ["id" => $user_id]) }}">詳細画面へのリンク</a>edit(編集画面)
リンク
<a href="{{ route("user.edit", ["id" => $user_id]) }}">詳細画面へのリンク</a>update(更新処理)
form
<form action="{{ route("user.update", ["id" => $user_id]) }}" action="post"> @csrf @method('PUT')delete(削除処理)
form
<form action="{{ route("user.destroy", ["id" => $user_id]) }}" action="post"> @csrf @method('DELETE')Controller
UserController
UserController<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class UserController extends Controller { public function index() { return view('user.index'); } public function create() { return view('user.create'); } public function store(Request $request) { // 作成処理 } public function show($id) { return view('user.show', [ 'user_id' => $id ]); } public function edit($id) { return view('user.edit', [ 'user_id' => $id ]); } public function update(Request $request, $id) { // 更新処理 } public function destroy($id) { // 削除処理 } }ルーティング
web.php
web.phpRoute::resource('user', 'UserController');
制限する時
web.phpRoute::resource('user', 'UserController', ['only' => ['index', 'show']]);