とある神戸大生の走り書き

主にプログラミングに関して、学んだことを走り書きとして残していきます。

Sansanのエンジニアサマーインターンに行ってきた!!!

こんにちは、神戸大学に通う大学3年生のTaKO8Kiです。 先日、Sansanで2週間の就業型インターンをしてきたので、振り返ります!

f:id:TaKO8Ki:20191007115300p:plain


目次


エントリー

僕は、wantedlyでスカウトをもらってエントリーすることにしました。

www.wantedly.com

選考の流れ的には、下のような感じです。

  1. 電話面談でインターンについての説明を受ける。(選考要素無し)
  2. エントリーシート的なやつを提出する。
  3. エンジニアの方と一対一で面接する。
  4. 参加決定

参加

どんなインターン

  • 期間 : 二週間から1ヶ月
  • 報酬 : 時給2000円(就業時間9:30~18:00)
  • 遠方からの参加の場合東京までの交通費支給と宿泊場所手配
  • 詳しくはこちらへ

取り組んだタスク

f:id:TaKO8Ki:20191007112814p:plainf:id:TaKO8Ki:20191007112818p:plain

僕はEight事業部の企業プレミアム(通称企プレ)チームに配属されて、

「企プレの業務フローの改善」

に取り組みました。

Eight事業部では、RailsとReact.jsを主に使用しており、Rspecをゴリゴリ書いていました。 ちなみにSansan事業部では、C#を使っているらしい。

取り組んだタスク的にあまり詳しく話せないのが残念ですが、
実装した機能は最終日前日にはリリースすることができたので、
非常にやりきった感がありました。

開発の感想

  • コードレビュー

基本的にGit flowで開発を進めました。
最低でも二人にはコードレビューを受けるという風になっていたので、 いかにレビューしやすいプルリクを受けるかを考えるようにしました。

  • QAエンジニアすごい!

普段のバイトでは、それなりに自分で動作確認をして最低限のコードレビューを受けてリリースみたいなプロセスでしたが、正直本当に動くのか不安な部分はいつもあったので、そのプロセスの中にQAエンジニアの方が入るだけで品質が格段に上がることを実感しました。

  • サービスを作るのはエンジニアだけじゃない

当たり前のようであまり考えたことが無かったのですが、エンジニアだけじゃなくて営業やCSなどの他の職種の方もサービスを作る一員であり、どこまでの作業をCSの業務フローで行い、どこまでをコードを書くことで処理するかみたいな部分はとても大事だなと感じました。

その他

ランチがすごく美味しかった

2週間のインターン期間の平日は全てランチをご馳走になりました!
インターンに参加するようになって改めて思いますが、食費がかかるかかからないかって意外と大きいと思うので、非常にありがたかったです。
あと、ランチではいろんな方と話すことができました。
Eightの取締役の塩見さんやCTOの藤倉さんや他にも、僕が自作キーボードに詳しい人と話してみたいと人事の方にリクエストするとそういった機会を設けてもらうこともできました。
人の話や意見を聞くのが割と好きなのでランチはとてもいい時間でした。

ランチスケジュール

日目 ランチ
1 焼肉
2 いい感じの和食
3 焼肉ではないけど肉
4 マグロ
5 忘れた
6 お蕎麦
7 焼肉
8 別の焼肉
9 焼肉弁当
10 お寿司

聞くところによると、discordの自作キーボードコミュニティがあるらしいですね。

biacco42.hatenablog.com

開発以外の時間もすごく充実していた

Sansanではストレングスファインダーやエニアグラムを大事にしており、 それらを元に「強マッチ」という自分の内面についてプレゼンするみたいなものがありました。

僕も簡易的な強マッチを行わせていただいたのですが、自分がどんな人間なのかを改めて考えて、他の人にプレゼンするのはすごく新鮮でした。基本的に自分のことを周りの人に話さないタイプなので、久しぶりに自分をテーマにして話した気がします。

ちなみに僕のストレングスファインダーは、こんな感じでした。

f:id:TaKO8Ki:20191007112154p:plain

最後に

始めての就業型インターンでしたが、実際の開発工程に携わることができ、最終的にリリースでき、少しでもEightというサービスに貢献できたことが何よりも嬉しかったです。
改めてメンターの鈴木さん、チームの皆さんありがとうございました!
すごくオススメのインターンなので、みんなも行こう!

f:id:TaKO8Ki:20191007120342p:plain
成果発表の様子

学生の時にEightを使っておくことをオススメされたので、僕もオススメしておきます。

8card.net

Treasureでほぼ定時退社を守りきって優秀賞を貰った|VOYAGE GROUP サマーインターン

こんにちは、神戸大学に通う大学3年生のTaKO8Kiです。

8/12から8/30でTreasureに参加してきました! 現在、それの続きで別のインターンに参加しているのですが、うまく時間が取れそうなので、Treasureを振り返ってみようと思います!


目次


エントリー

Treasureというインターンを初めて知ったのはサポーターズのエンジニアキャリアセミナーというイベントでした。
結果的にそのイベント経由でエントリーを行い、一回2時間くらいの面接をして、最終的に参加することになったような気がします。(確か4月くらいに面接を受けたので、正直ほとんど記憶にないです。。割と長めの面接だったことだけは覚えています。)

参加

Treasureとは?

  • 期間 : 三週間
  • 前半 (7日間) : 講義、後半 (8日間) : チーム開発
  • 参加人数 : 約30人
  • 報酬 : 12万円
  • 遠方からの参加の場合東京までの交通費支給
  • 詳しくはこちらへ

宿泊は、シェアハウスを用意していただきました!
最初は集団で生活することに不安がありましたが、慣れればなんてことはなく、楽しかったです!

また、今回から新オフィスでのTreasureでした!

f:id:TaKO8Ki:20190908230225j:plain

講義パート

講義は、Golang入門から始まり、フロントの講義(JavaScript, React)、DB設計の講義、セキュリティの講義、インフラの講義、認証の講義、アイデア出しの講義などがありました。

講義パートの感想

どの講義も爆速で進んでいったのですが、非常に内容が濃く、圧倒的に成長できた気がします。 中でも僕が一番印象的だったのは、アイデア出しの講義でした。 普段から個人開発でアイデアを出すのは好きですが、体系立ててアイデアを出したことが今までなかったので、非常に参考になりました!

チーム開発パート

講義パートが終わった後に五人一組のチームが発表されました。
それぞれのチームがそれぞれのチーム名とsoul(チームが目指すものを一言でまとめたやつ)を掲げてサービス開発に望みます。
僕がいたチームは「menhela」という名前で、soulはより「よりスマートに、よりコンパクトに。」です。普段は物静かだけど、熱中することにはとことん熱中するというチームメイトの共通点からこのチーム名が生まれました。

作ったもの

「スマート通告」というサービスを作りました!

特定のツイートなどによって誹謗中傷などを受けた方が、写真右の通告書(「該当ツイートを消さないと法的処置をとるよ」という内容のもので、これを相手に送りつけることでツイートを削除することを狙っています。)を作成するのをサポートするサービスです。
作った通告書はPDFやPNGでダウンロードできたり、リンクで共有できたりするので、それらを相手に送りつけます!

f:id:TaKO8Ki:20190908222947p:plainf:id:TaKO8Ki:20190908223200p:plain

なんとなく僕が出したアイデアが元になったのですが、チームメンバーがいい感じにまとめてくれたので非常にありがたかったです。
ちなみに原案は「ワンクリックで誰かを民事訴訟できるサービス」です。 割と気に入っているので、いつか実現できたらなーと思っています。

チーム開発パートの感想

合計6チームあり、チームによって開発スタイルは色々あったと思いますが、僕達はフロントエンド3人(React)とバックエンド2人(Golang)でGitHub Flowでチーム開発を進めました。 僕達menhelaは基本的に定時退社をしていたので、夜通し開発みたいなことは一切なく、めちゃめちゃホワイト企業でした。

サポーターの方々の的確なアドバイスもあり、最終日まで非常に順調に開発を進めて、それをプレゼンして、最優秀賞の次の優秀賞をいただきました!
soulの通りスマートでコンパクトなチーム開発だったと思います。 また、自分が開発に関わったサービスが具体的に誰かに評価されたのは初めてだったので、達成感があったのを覚えています。

その他

参加している人のレベルがすごく高くてとてもいい影響を受けました!
それに関連して、自分が開発する環境を自分好みにカスタマイズするのって結構大事だなーと思いました。(自作キーボードとかターミナルのカスタマイズとか。)それだけで開発効率が結構上がったりしました。

それ以外に結構印象的だったのが、Treasureの講師の方や参加者にはvimmerが結構いました。すごくかっこいいなーと思いながら眺めてましたが、僕はもう少しvscodeでいこうと思います!

最後に

すごく楽しい三週間でした!技術だけでなく開発の進め方やアイデアの出し方など色々と身に付けることができたと思います。誰かにオススメしたくなるインターンです!

他のTreasure生のブログ記事をまとめようかなと思ったのですが、把握しきれていないので、うまくまとめてあるブログ記事を一つ載せておきます! 最後の方に他のTreasure生のブログ記事まとめがあります!

note.mu

プログラミング始めて一年でサマーインターンの選考を受けまくった結果

こんにちは、TaKO8Kiです。

僕は、神戸大学工学部市民工学科に通う大学3年生です。
2018年6月からサーバーサイドエンジニアを目指して、Rubyを書き始めてだいたい一年が経ちました。

最近までサマーインターンの選考を受けていたのですが、だんだん落ち着いてきたので、振り返ってみようと思います。


目次



受けたサマーインターン

若干受けすぎた感が否めないですが、最終的には意外と上手くいきました。

どうやって受けるインターンを決めたか

どの企業の方とも1on1面談でお話しする機会があったので、その時に聞いた会社の雰囲気などを参考にしてなんとなくで決めました。

サマーインターンの情報を集めるために利用したサービス

エンジニアの逆求人系のサービスで有名な3つを利用しました。 どのサービスでも企業との1on1面談ができる点が非常に良かったです。

受けるインターンを分類

どの選考を受けるにしても、つよつよ高専生や大学生と対戦することになるわけなので、それなりに頑張らないといけないのは当たり前なのですが、一応、下記のように「頑張れば受かりそうなインターン「受かったら万々インターンに分けて選考に臨みました。

この分類は、自分の今の実力とコーディングテストの難易度やその他選考の傾向を元に行いました。

頑張れば受かりそうなインターン

受かったら万々インターン

選考結果

結果は、5ACでした。
頑張れば受かりそうなインターンは、4/5ACで、
受かったら万々インターンは、1/4ACだったので 、ある程度予想通りでした。

インターン 合否 参加するかどうか
Treasure 参加
Wantedlyの就業型インターン 参加
Sansanの就業型インターン 参加
Cybozuの3日間のインターンWEBサービス開発) × -
サイバーエージェントハッカソン形式のインターン 参加
アカツキの就業型インターン × -
DeNAプロダクト開発コース 辞退
LINEの就業型インターン × -
SmartNewsの就業型インターン × -

できれば、合格したインターン全てに参加したかったのですが、他のインターンとの兼ね合いもあってDeNAプロダクト開発コースには参加できませんでした。ごめんなさい。。

サマーインターンの選考を受けての反省

やはりコーディングテストが一番の難関になるように感じました。
ガチガチにアルゴリズムの理解を問うてくるようなテストの場合は、競プロに慣れ親しんでいないと厳しいと思いました。。

サマーインターン選考前後で変わったこと

一番大きい変化は、競プロ(主にAtCoder)を始めたことです。(後2, 3回で緑色になりそう!)

atcoder.jp

f:id:TaKO8Ki:20190803142700p:plain

なんとなく必要そうだから始めた競プロでしたが、今では1日1, 2問解いていて、ある意味、趣味みたいになりました。

最後に

ここまで読んでいただきありがとうございました!
もう少しでサマーインターンが開始するので、今後も頑張っていこうと思います!

普段は、個人開発でサービスを作ったり、自然言語処理を勉強したりしています!

twitter.com

MacOSでpipを使ってCaboChaをインストールしようしてエラーがでた時にやったこと。

エラーが出た時の状況

最近、言語処理100本ノックを解いていて、5章でCaboChaを使うことになったのですが、下記を参考にしてインストールしようとしたところエラーが発生。

qiita.com

エラー自体をコピーしておくのを忘れてしまったのですが、なんとなく、 下記のコマンドを実行した時にbuildが失敗しているみたい。

pip install cabocha-master/python/

解決策

Command Line Toolsのバージョンを9.4に下げた。

下記のリンクで「Command Line Tools 9.4」みたいに検索してインストールしたらバージョンを下げられる。 その後、同じようにコマンドを実行したらエラーが発生しなかった。
https://developer.apple.com/download/more/

参考

www.cl.ecei.tohoku.ac.jp

teratail.com

taku910.github.io

Golangを始めて少し経ったので、WebSocketを使ってリアルタイムタスク管理アプリを作った。

Golang初めて1、2ヶ月ほど経ったので、Asana風なリアルタイムタスク管理アプリを作ってみました。 ちなみにAsanaはこんな感じのやつです。 デザインが好きなので、個人的に使ってます。 asana.com

目的

今回は実際にデプロイして使ってもらうことが目的ではなく、GitHubでコードを公開すること・Golangに慣れること・WebSocketに触れることを目的にしました。

作ったもの

Image from Gyazo

github.com

こんな感じのやつを作りました。 ユーザーごとにタスクを追加したり、削除したりできるようになっていて、それがリアルタイムで他のユーザーにも反映されるようになっています。 DBには接続していないので、CSSのクラス名でそれぞれのタスクを管理しています。

具体的には、作成した順番にタスクにCSSのクラス名としてIDが割り振られるようになっています。

例:

  • 最初に作ったタスクは、クラス名task1。
  • 二つ目に作ったタスクは、クラス名task2。
  • 次にtask1を削除して、三つ目のタスクを作るとクラス名がtask3になる。

デザインはRESUMEの感じが好きなので、それを参考にしています。

Golangで書いたコード

クリックしてコードを見ることができます。

handler.go

package main

import (
    "html/template"
    "net/http"
    "path/filepath"
    "sync"
)

/*
HTMLテンプレートをサーブするためのハンドラ
*/
type templateHandler struct {
    once     sync.Once          //HTMLテンプレートを1度だけコンパイルするための指定
    filename string             //テンプレートとしてHTMLファイル名を指定
    tmpl     *template.Template //テンプレート
}

/* templateHandlerをhttp.Handleに適合させるため、ServeHttpを実装する */
func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

    // テンプレートディレクトリを指定する
    path, err := filepath.Abs("./templates/")
    if err != nil {
        panic(err)
    }

    // 指定された名称のテンプレートファイルを一度だけコンパイルする
    t.once.Do(
        func() {
            t.tmpl = template.Must(template.ParseFiles(path + t.filename))
        })

    t.tmpl.Execute(w, nil)
}

main.go

package main

import (
    "log"
    "net/http"
)

func main() {

    /* ルートへのアクセスに対してハンドラを貼り、group.htmlをサーブする */
    http.Handle("/", &templateHandler{filename: "/group.html"})

    group := newRoom()

    http.Handle("/room", group)

    go group.run()

    /* webサーバを開始する */
    log.Println("webサーバを開始します。")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatalln("webサーバの起動に失敗しました。:", err)
    }
}

task.go

package main

type task struct {
    Name   string
    Detail string
    Delete string
}

group.go

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/websocket"
)

const (
    socketBufferSize = 1024
    taskBufferSize   = 256
)

/* websocket用の変数 */
var upgrader = &websocket.Upgrader{
    ReadBufferSize:  socketBufferSize,
    WriteBufferSize: socketBufferSize,
}

type group struct {
    forward chan *task
    join    chan *client
    leave   chan *client
    clients map[*client]bool
}

/*
groupをhttp.handleに適合させる。
ここでは以下のことを実装する。
   ・websocketの開設
   ・clientの生成
*/
func (c *group) ServeHTTP(w http.ResponseWriter, r *http.Request) {

    /* websocketの開設 */
    socket, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Fatalln("websocketの開設に失敗しました。:", err)
    }

    /* クライアントの生成 */
    client := &client{
        socket: socket,
        send:   make(chan *task, taskBufferSize),
        room:   c,
    }

    c.join <- client
    defer func() {
        c.leave <- client
    }()

    go client.write()
    client.read()
}

func newRoom() *group {
    fmt.Println("groupが生成されました。:", t.Format(layout))
    return &group{
        forward: make(chan *task),
        join:    make(chan *client),
        leave:   make(chan *client),
        clients: make(map[*client]bool),
    }
}

func (c *group) run() {
    for {
        // チャネルの動きを監視し、処理を決定する
        select {

        /* joinチャネルに動きがあった場合(クライアントの入室) */
        case client := <-c.join:
            // クライアントmapのbool値を真にする
            c.clients[client] = true
            fmt.Printf("クライアントが入室しました。現在 %x 人のクライアントが存在します。\n",
                len(c.clients))

        /* leaveチャネルに動きがあった場合(クライアントの退室) */
        case client := <-c.leave:
            // クライアントmapから対象クライアントを削除する
            delete(c.clients, client)
            fmt.Printf("クライアントが退室しました。現在 %x 人のクライアントが存在します。\n",
                len(c.clients))

        /* forwardチャネルに動きがあった場合(タスクの受信) */
        case msg := <-c.forward:
            fmt.Println("タスクを受信しました。")
            // 存在するクライアント全てに対してタスクを送信する
            for target := range c.clients {
                select {
                case target.send <- msg:
                    fmt.Println("タスクの送信に成功しました。")
                default:
                    fmt.Println("タスクの送信に失敗しました。")
                    delete(c.clients, target)
                }
            }
        }
    }
}

大まかには以上です。

READMEに実行の仕方が書いてあるので、もし興味があれば見てみてください。

参考

[ golang ] WebSocketを使ったチャット機能を実装してみる。 | Wild Data Chase -データを巡る冒険-