Scala再入門メモ:その1
挫折したままにしておくのはもったいない気がしてきたので。
超・基礎の基礎から再入門する。
資料: https://dwango.github.io/scala_text/
sbt consoleの起動
初回起動はとても時間がかかった。
$ sbt console Getting org.scala-sbt sbt 0.13.9 ... downloading https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt/0.13.9/jars/sbt.jar ... [SUCCESSFUL ] org.scala-sbt#sbt;0.13.9!sbt.jar (3893ms) downloading https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/main/0.13.9/jars/main.jar ... [SUCCESSFUL ] org.scala-sbt#main;0.13.9!main.jar (8053ms) downloading https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/compiler-interface/0.13.9/jars/compiler-interface-bin.jar ... [SUCCESSFUL ] org.scala-sbt#compiler-interface;0.13.9!compiler-interface-bin.jar (4261ms) downloading https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/compiler-interface/0.13.9/jars/compiler-interface-src.jar ... [SUCCESSFUL ] org.scala-sbt#compiler-interface;0.13.9!compiler-interface-src.jar (4059ms) ・・・略・・・ downloading https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/cross/0.13.9/jars/cross.jar ... [SUCCESSFUL ] org.scala-sbt#cross;0.13.9!cross.jar (4000ms) downloading https://jcenter.bintray.com/org/scala-sbt/ivy/ivy/2.3.0-sbt-c5d1b95fdcc1e1007740ffbecf4eb07abc51ec93/ivy-2.3.0-sbt-c5d1b95fdcc1e1007740ffbecf4eb07abc51ec93.jar ... [SUCCESSFUL ] org.scala-sbt.ivy#ivy;2.3.0-sbt-c5d1b95fdcc1e1007740ffbecf4eb07abc51ec93!ivy.jar (1982ms) downloading https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/cache/0.13.9/jars/cache.jar ... [SUCCESSFUL ] org.scala-sbt#cache;0.13.9!cache.jar (4282ms) downloading https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/test-agent/0.13.9/jars/test-agent.jar ... [SUCCESSFUL ] org.scala-sbt#test-agent;0.13.9!test-agent.jar (4725ms) downloading https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/apply-macro/0.13.9/jars/apply-macro.jar ... [SUCCESSFUL ] org.scala-sbt#apply-macro;0.13.9!apply-macro.jar (4058ms) :: retrieving :: org.scala-sbt#boot-app confs: [default] 52 artifacts copied, 0 already retrieved (17785kB/527ms) Getting Scala 2.10.5 (for sbt)... downloading https://jcenter.bintray.com/org/scala-lang/jline/2.10.5/jline-2.10.5.jar ... [SUCCESSFUL ] org.scala-lang#jline;2.10.5!jline.jar (1155ms) :: retrieving :: org.scala-sbt#boot-scala confs: [default] 5 artifacts copied, 0 already retrieved (24493kB/211ms) [info] Set current project to work (in build file:/Users/maetoo11/work/) [info] Updating {file:/Users/maetoo11/work/}work... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Starting scala interpreter... [info] Welcome to Scala version 2.10.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45). Type in expressions to have them evaluated. Type :help for more information. scala>
Visual Studio Codeのシンタックスハイライトプラグイン
Visual Studio CodeでScalaを書くなら、下記プラグインを入れるとよい。
Scala | Visual Studio Marketplace
フォールスルーとは?
Switchの「フォールスルー」って何?
JavaとかCではフォールスルーの動作があると記載されていた。
こういうやつのことらしい。
int value = 0; switch (value) { case 0: case 10: // 処理1 break; default: // 処理2 }
参考:Java の switch 構文落とし穴 - Status Code 303 - See Other
「束縛される」とは?
var i = 0 というのは、"iという変数に0というIntのオブジェクトをbind(束縛)した" ということになる
scalaでは、なぜインクリメントやデクリメントができないのか? - scalaとか・・・ より
確かにインクリメント書いたらエラーになったな…。
「代入以外の方法で束縛できない」という部分で納得できた。
Listを引数でとるとき
下記のように書くと type List takes type parameters
というエラーが出る。
def func(list: List) = { // 処理 }
型を指定しなさいということ。
def func(list: List[String]) = { // 処理 }
いま働いている環境について
一緒に働いてくださる方をTwitterで募集したので、今私が働いている環境をまとめてみました。
やっていること
社内請求システムの開発をしています。
2016年5月にリリースしており、請求担当者や営業担当者の要望を聞きながら機能追加を行っています。
- Ruby on Rails
- AWS(Elastic Beanstalk、RDS)
- MySQL
テクニカルなことはしていないRuby on Railsでつくられたシンプルなシステムです。
システムの名前は 秩序 です。
これは社内に秩序をもたらせるように頑張ろうという想いが込められています。
下の画像はボツになったロゴです。
弊社のメインのプロダクトは現在1つで、私以外のエンジニアは基本的にその製品の機能追加・改良を行っています。
私も現在のプロジェクトに着手する前はそのプロダクトの開発をしていました。
女性のエンジニアは2016/6/24時点で1人です。
同じ会社のコンサルタントチーム、バックオフィスチームには女性がいます。
環境・雰囲気について
◆出社時間は自由
(一応10:00〜19:00が就業時間らしいです。)
早めに出社して早めに帰る人、14:00頃から出社する人、早めに帰る人、など色々な勤務時間の人がいます。
打ち合わせがある場合などは、皆さんきちんと時間にあわせて出社します。
◆気が向いた日は自宅でお仕事したりカフェでお仕事したりもOK
自宅でお仕事ができます。
私自身も朝は自宅で洗濯機をまわしつつ仕事をして、お昼前から出社したりします。
カフェで集中して仕事をする人や海辺で仕事をする人もいます。
◆グループ会社のエンジニアとも交流できる
グループ会社の企業3社が同じオフィスビル内にいるので他社のエンジニアと交流できます。
グループ会社が開発しているサービスやアプリは自分の会社とは全然違うものもあるので、色々な技術に触れられます。
社内のエンジニア交流会(LT大会のようなもの)も開催しています。
◆エンジニアがそれぞれ特定分野に尖っていて面白い
静的型付けの力を信じている人、Rubyに詳しい人、インフラを見守り操る人、文書作成が得意な人などそれぞれ何か自分の得意なことを持っています。
もちろん、修行中のエンジニアの卵もいます。
◆チーム間での雰囲気が悪くない
エンジニアだけではなく営業、コンサルタントの人も社内にはいますが、お互い協力して仕事をすすめています。
◆喧嘩や言い争いではなく議論ができる
「私はこう思う」を言いやすい雰囲気です。
お互い自分の意見を言った上で最適解をさがしたり、相手の意見のほうがいいアイデアだと思えばそちらを採用したりします。
もちろん、怒鳴るような人はいません。
(笑い声が大きい人は何人かいます)
◆チャレンジウェルカム
特定の言語やツール、フレームワークに縛られていません。
例えば、現在社内ではRubyを採用していたプロダクトの一部をScalaに書き換えるプロジェクトが進んでいます。
◆レジャーや飲み会を強制しない
会社のメンバーでキャンプや登山などをしている人もいますが、参加していない人もいます。
無理やり誘う雰囲気がなくて私は好きです。
飲み会も参加できる人だけ参加すればいいよね、という感じです。
◆それぞれが大切にしているものを尊重している
奥さまの体調が悪いときは自宅でお仕事をする、お子さんの体調が悪いときはお休みする、勉強会に参加するのが好きだから早めにあがる、など色々な働き方をしていますがお互いに文句をいうことはありません。
それぞれが大切にしているものを尊重しあっています。
おまけ
弊社のCTOについてLTでお話したときのスライドです。
www.slideshare.netこのスライドの最後のほうに書いてある「請求フローを整理するプロジェクト」が発展して、社内システムを開発することになりました。
手を挙げたことに対して責任をもって取り組むことができていて、とても楽しいです!!
補足
ゆるい会社というわけではなく、成果を出すために自分にとってやりやすい働き方を選んだほうがいいよね、という考えのチームだと思います。
やるときはやります。
ただ、働き方を自分で決められるおかげで、忙しい時期に洗濯物を溜めずに済むのはなんと嬉しいことか…!!
家事のことを忘れ、集中してプログラムを書くのが私にとってはとても成果が出しやすいと思っています。
コミットコメントに絵文字プレフィックスをつけてみた話
きっかけ
きっかけはこんなツイートを見かけたことから。
最近ProttでコミットにEmoji Prefixつけ始めたんだけど、視認性いいし、ひとつのコミットでひとつの変更をすることを意識できるからチームでコミットの粒度も綺麗になってきてかなりいい感じ。あとなんかログが見てて楽しい(重要) pic.twitter.com/2oWwMBDfIu
— よしこ (@yoshiko_pg) 2016年6月1日
「コミットコメントに絵文字!!超可愛いじゃんΣ(゚∀゚ノ)ノキャー」と思って取り入れてみることにしました。
プロジェクトの概要
- 社内向けシステム構築
- 開発担当は私1人
- 悩んだら周りの別プロジェクトをすすめている先輩に相談
- 1人で実装して1人でリリース
- たまに先輩がレビューしてくださる
ルール
元々は
- Fix:修正
- Mod:改善、変更
- Add:新しい機能やファイルの追加
という文字のプレフィックスをつけていました。
取り入れた様子
確かにコミットログが華やかになりました。
しかし、絵文字プレフィックスはやめることに!!
なぜ、絵文字プレフィックスをやめるのか
理由は2点あります。
- このコミットにはどの絵文字をつければいいんだっけ?と考える時間が発生してしまった。
- GitHub上だけではなくコンソールでgitのログを確認することもあるので絵文字プレフィックスだと意味がわかりにくい。
1人でざくざく進めたいプロジェクトなので、合わなかったのかもしれません。
GitHubのログを華やかにしたい人のために、FixとかModなどの文字プレフィックスを絵文字に変換して表示してくれるChrome拡張があってもいいのかもしれない、と思いました。
解決済み:cancancanでread権限を設定してもあるページが閲覧できない
2016/5/18に解決しました。
原因と解決方法は下部に記載しています。
やろうとしていること
CanCanCanという権限管理のgemを使用し、権限ごとにModelの操作に制限をつけようとしている。
GitHub - CanCanCommunity/cancancan: Continuation of CanCan, the authorization Gem for Ruby on Rails.
環境
困っていること
あるModelのついて閲覧(read)のみ可能にしたい場合、
readのみ許可では権限がないことになってしまう。
現在は一旦全アクションに対して権限を付与(manage)し、禁止したいアクションをcannotで指定するという形をとっている。
正しく動作しない例:
if user.admin? can :manage, :all elsif user.member? can :read, [Hoge, Humu] end
現在の暫定的な対処:
if user.admin? can :manage, :all elsif user.member? can :manage, [Hoge, Humu] cannot [:create, :update, :destroy], [Hoge, Humu] end
上記の正しく動作しない例の状態で、Hogeを閲覧するようなページに遷移すると
権限がないためエラーメッセージが表示される。
「You are not authorized to access this page.」
readを許可するだけでは閲覧は許可されないのかを知りたい。
参考にしたサイト
- Rails: CanCanでアクションごとに権限を設定する方法 - Qiita
- How to use CanCan / CanCanCan - Qiita
- Rails4でCanCanCanによる権限管理 [俺の備忘録]
解決した内容(2016/5/18追記)
原因
該当ページ閲覧時に独自で作成したアクションが呼び出されるようになっていたため。
独自のアクションも許可する必要があった。
解決方法
if user.admin? can :manage, :all elsif user.member? can [:read, :original_acthion], [Hoge, Humu] end
調査は下記ページを参考に行った。
Debugging Abilities · CanCanCommunity/cancancan Wiki · GitHub
デバッグログは上記ページを参考にした。
Rails.logger.debug "Access denied on #{exception.action} #{exception.subject.inspect}"
これで「どのモデル」の「どのアクション」に権限がないのかがわかった。
るっびー先輩、ありがとうございました。
社内勉強会で感動した話(DDD ユビキタス言語再考)
社内勉強会で先輩がお話していた内容に感動しました。
先輩のプレゼンに感動して泣きそう(´;ω;`)ブワッ
— まえとー (@maetoo11) 2016年5月12日
内容の解説ではなく、自分が思ったことを書くので他の人の役には立たないかもしれないです。
また、勉強会は社内クローズドなイベントでしたが、
先輩のスライドはSpeaker Deckというサービスで公開されており、
ブログに書いても良いという許可もご本人にいただいております。
先輩は下記のスライドをもとに発表していました。
どこに感動したのか
ユビキタス言語はチーム全員で合意し創るもの
ユーザーの言語 = ユビキタス言語 というわけではない
という部分に感動した。
感動というか「今ならわかる!」と思った。
なぜ感動したのか(なぜ今ならわかるのか)
多分、似たような話を半年ほど前にも社内勉強会でお話してもらったと思う。
でも、そのときの私は「ユビキタス言語??言葉そんなに大事なの????」という感じだった。
ここ3ヶ月、私は社内向けのシステムを開発している。
(そのシステムは経理担当者や営業担当者がExcelを用いて手動で行っていることをシステム化&一部自動化を目指している。)
ヒアリングを行い、システムの構造を考えていく中で、社内でAと呼んでいた書類が実は一般的にはBという書類とCという書類があってそれを組み合わせたものだということがわかる場面があった。(業務としてもB、Cの書類を発行すべきだった)
担当者から言われた書類の名前をそのまま使うのではなく、どうあるべきかということも担当者やその他関係するメンバーと考えながら認識をすりあわせて行くことができた。
同じ認識になった言葉をつかうと、資料つくりも楽で、認識の齟齬も減った気がする。
その実体験があったから「今ならわかる!」と思えたのだろう。
昔はわからなかったことでも、自分が体験すると理解しやすくなることもあるのかもしれない。
疑問(内容には関係ない可能性あり)
今回の発表内容には関係ないかもしれないが、下記のような疑問がある。
システム化するにあたり、社内オリジナルの名前で英語に直訳できないモデルの名前はどうすればいいのだろう?
(今は無理やり英訳した長い名前をつけている)
railsについて、先輩にもらったアドバイスまとめ(その1)
最近はRuby on Railsで社内システムを作っています。 その中で先輩からもらったアドバイスやレビューで受けた指摘をまとめます。
new()はいらない
hoge = Hoge.new()
は
hoge = Hoge.new
でよい。
(Rubyは短く楽に書けるときは楽をするのじゃ!)
is_available?のisはいらない
有効かを判定しtrue/falseを返却するようなメソッドの名前は
def is_available? # 何らかの処理 end
ではなく
def available? # 何らかの処理 end
でよい。
(present?やblank?というメソッドがありますよねー)
※私はこの「?」を疑問形の「?」だと思っていました…(Is this a pen?的な)
破壊的でないメソッドに「!」はいらない
def hoge! # 破壊的な処理 end
であり、破壊的でないメソッドに「!」はいらない。
(破壊的な処理を行う場合はprivateメソッドであっても「!」をつけるようにしています)
ある機能追加のために複数のテーブルにカラム追加を行う場合、migrateファイルは分ける
分けたのですが理由が思い出せず…。
※これはもしかしたら1つの機能追加で複数のテーブルに手が入ったことをわかりやすくするために、migrateファイルはわけないほうがよかったのかも?と思いました。
できるだけ短く、意味のある処理ごとにメソッドにする
def calc_hoge hoge = 0 hoge = hoge + (a * b) hoge = hoge + (c * d) end
は
def calc_hoge hoge = 0 hoge += calc_a_b hoge += calc_c_d end def calc_a_b a * b end def calc_c_d c * d end
のようにしたほうがコードが説明的になってわかりやすい。
2016/4/19(火)追記
ステータスコード404でリソースの存在を隠すこともできる
現在作成しているシステムはユーザーにロールを設定しており、ロールによっては閲覧できないリソースがある。
そのリソースを表示するようなページに権限のないユーザーがアクセスした場合、
403が返るとリソースが存在していることが権限のないユーザーにも分かってしまう。
存在自体を隠したいときは404を返す。
詳しくは下記の記事を参照
HTTPステータスコードを適切に選ぶためのフローチャート : 難しく考えるのをやめよう | インフラ・ミドルウェア | POSTD
railsで404のときに表示されるページは public/404.html
である。
任意のデザインにしたい場合は404.htmlを編集すればよい。
rspecのテストでカバレッジが計測できるgem、SimpleCovを導入する
テストを書くならカバレッジ計測と行単位で通った・通ってないの確認ができたらいいな、と思っていたら
@tmtms さんより「SimpleCov」を教えていただきました。
導入手順
Gemfileに「simplecov」を追加
group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' gem 'rspec-rails' # Test format nyan cat gem 'nyan-cat-formatter' # テストを自動実行 gem 'spring-commands-rspec' gem 'guard-rspec', require: false # カバレッジ取得 gem "simplecov" # モデルにテーブルのカラムをコメントで出力 gem 'annotate' end
gemをインストール
$ bundle install --path vendor/bundle --jobs=4 $ # .bundle/configに設定されている場合はbundleでOK
spec/spec_helper.rbにsimplecovのstartを記述
require 'simplecov' SimpleCov.start 'rails' RSpec.configure do |config| # rspec-expectations config goes here. You can use an alternate #・・・略・・・
これで準備は完了
使い方
rspecでテストを実行する。
$ bundle exec rspec spec/
するとプロジェクトフォルダ直下に「coverage」というフォルダが作成される。
coverageフォルダ配下の「index.html」をブラウザで開く。
するとファイルごとのカバレッジ一覧が表示される。
ファイル名をクリックすれば、行単位で通った・通っていないが確認できる。
導入にあたり参考にしたサイト