#100DaysOfDesign Figmaでデザインの練習はじめた
デザイン学習はじめた。
目的は、以下の2つ
1. デザイナーの仕事を巻き取って、スピードを上げたい。
社内のデザイナーがパツパツのため、 重要度の低いデザインのしごとを自分で巻きとり、自己完結してスピードをあげたい。
2. 自分の独自の強みとしたい。
機械学習やらアルゴリズムごりごりエンジニアの方面では、数学ニガテな自分では勝てない。 サーバーサイドエンジニアがやりたがらないデザインの方面で1つ強みを形成しくという戦略。 スライドデザインとかは得意だったので適正もあると判断した。
FIgmaでデザイン学習開始
Figmaというツールでデザインの学習をはじめた。 このツール、Webエンジニアがちょこっとデザインを学びたい時には最高だと思う。 理由は2つ
1. (今の所)無料である
Adobeはいわずもがな高い。Sketchは年9000円かかる。 一方でFigmaは今のところ無料である。
2. 同時編集できる。
スプレッドシートのように同時編集ができる。 社内のデザイナーにレビューをもらうのがめちゃくちゃ楽そう。
使い勝手はとてもよかった。
直近の目標を掲げる。 短期目標: 今月で10個のProductを上げること。 中期目標: 今年度中に50個のProductをあげること。
【初心者向け】ajaxハンズオン with Rails5.1/ jQuery3.0
初心者向け
プログラミング学びたての方から、ajaxがよくわからないという相談を Web上を見るとajaxの詳しい解説はあっても、ハンズオン形式の記事は少ないと感じました。 ということで、細かい説明は抜きにしてとりあえず動くことを重視した記事を作成しました。
対象
ターゲット
- Ruby on Rails学習中のプログラミング初学者(累計学習時間50h ~ 100h)
- jQueryは少しだけ触ったことがある。
環境
- Ruby on Rails(5.1系)
- MySQL5.6 ※4系向けにも少し細くします。
作成するもの
最小限のTodo管理アプリを作成します。 細かいことは説明しない代わりに、はじめての方でも作りきれるように 過程を細かく載せていきます。
キーワード
gif
完成系のコード(Ajaxの部分)
$(document).ready(function() { $("#submit").on('click', function(e) { e.preventDefault(); var text = $('#task_title').val() $.ajax({ type: 'POST', url: '/tasks.json', data: { task: { title: text, } } }).done(function(data){ $('#task-list').append( `<tr> <td> ${data.title} </td> </tr>` ) }) $('#task_title').val('') }) })
1. アプリを作成する(rails new)
作成
rails new!
まずはアプリの型、作成からいきましょう。
rails newをしていきます。
rails new todo -d mysql
続いてデバッグ用に 'pry-rails' というgemをGemfileにいれておきましょう。
# Gemfile gem 'pry-rails'
bundle install
scaffoldで簡単にアプリを作成しよう!
Railsにはscaffoldという、アプリケーションの枠組みだけをコマンド一発で作成してくれる機能があります。 今回はajaxの練習であるため、サーバーサイドの記述は極力簡略化するために、このscaffoldを使いましょう!
scaffoldについての詳細はこちら Rails scaffoldを初心者向けに解説!実際にアプリを…|Udemy メディア
以下のコマンドを順に実行しましょう!
rails g scaffold task title:string #todoモデルを作成(titleというカラムをもたせる) rails db:create # データベース作成 rails db:migrate # マイグレーション実行
2. jQueryをCDNでインストールする(Rails5向け)
CDNによるjQueryインストール
※Rails4には デフォルトでjQueryが入っているため、この作業は飛ばしてください。
まずは、jQueryの公式サイトにいきましょう! jQuery CDN
jQuery 3.x のuncompressedを押すと表示されるリンクをコピーして、application.html.erbに貼り付けましょう!
3. jQueryの練習
JavaScriptファイルの作成
assets/javascripts 配下に tasks.js というファイルを作成しましょう! ※tasks.coffeeというファイルが自動生成されている場合は tasks.coffeeを削除してください。
$(document).ready(function() {})
tasks.jsに以下のように記述しましょう。
>||js||
$(document).ready(function() {
console.log("Hello World");
})
|
GoogleChromeの検証機能などで、確認しましょう!
$(document).ready(function() {})
この記述については詳細は割愛しますが。 "DOM要素(HTML)を全てよみこんでから、JavaScript実行する"ための記述です。
4. Ajaxについて
HTMLを書き換える
index.html.erbを以下のように書き換えましょう
<p id="notice"><%= notice %></p> <h1 id="title">Tasks</h1> <!-- scaffoldで自動生成したformを呼び出しましょう --> <%= render 'form', task: @task %> <table> <thead> <tr> <th>Title</th> <th colspan="3"></th> </tr> </thead> <!-- jQueryでDOMを取得できるようidを付与しましょう --> <tbody id="task-list"> <% @tasks.each do |task| %> <tr> <td><%= task.title %></td> </tr> <% end %> </tbody> </table> <br>
_form.html.erbを以下のように書き換えましょう
<%= form_with(model: task, local: true) do |form| %> <% if task.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(task.errors.count, "error") %> prohibited this task from being saved:</h2> <ul> <% task.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= form.label :title %> <!-- idを付与しましょう --> <%= form.text_field :title, id: :task_title %> </div> <div class="actions"> <!-- idを付与しましょう --> <%= form.submit "Submit", id: "submit" %> </div> <% end %>
tasks_controllerを以下のように編集しましょう
class TasksController < ApplicationController def index @tasks = Task.all @task = Task.new # _form.html.erbで使用する変数を定義 end end
onでイベント発火
JavaScript/jQueryでは〇〇を押したら~、◯◯の上にカーソルをのせたら、のようなタイミングをとることができます。 それをイベントの発火と呼びます。 「submitボタンを押したら、~~する 」を表すコードを on を使用して書いてみましょう。
tasks.jsを以下のように編集しましょう。
$(document).ready(function() { $("#submit").on('click', function(e) { //① e.preventDefault(); //② var text = $('#task_title').val() //③ console.log(text) }) })
①'submit'というidがついたDOMがクリックされたときに、第二引数にあたえられた関数(function)を実行します ②e.preventDefaultはsubmitボタンがDefaultでもっているページ遷移しようとする機能をキャンセルします ③'task_title'というidがついたDOM(今回の場合はinput)のvalueを取得します
ajaxでリクエスト
ajaxでtasks_controller#createアクションにリクエストを送っていきましょう!
tasks.jsを以下のように編集します
$(document).ready(function() { $("#submit").on('click', function(e) { e.preventDefault(); var text = $('#task_title').val() $.ajax({ type: 'POST', // ①HTTPメソッドを指定します。 url: '/tasks', // ②パスを指定します data: { // ③HTTPリクエストのボディを指定します。Railsではここで指定した値がparamsに入ります。 task: { title: text, } }, dataType: 'json' // ④HTTPリクエストで要求するdataのタイプを指定します。 }).done(function(data){ // ⑤リクエストに成功した場合 .done以下の関数が実行されます。 console.log(data) }) }) })
④ dataType: 'json'
dataType: 'json' は 「リクエストでhtmlではなくjsonを返してね」という意味になります。 これはtasks_controller#createの以下と対応しています。
def create @task = Task.new(task_params) respond_to do |format| if @task.save format.html { redirect_to @task, notice: 'Task was successfully created.' } format.json { render :show, status: :created, location: @task } # ここ! else format.html { render :new } format.json { render json: @task.errors, status: :unprocessable_entity } end end end
format.json というのが、jsonを求めるリクエストが来た場合です。 今回の場合はhtmlではなくjsonという形式でレスポンスを返す記述となっています。 jsonを生成するためにjbuilder(show.json.jbuilder)というものが使われていますが、今回はjbuillderに関する記述は割愛します。 jbuilderはjsonを整形して生成するために必要なもの、ぐらいに抑えておいてください。
⑤ done
リクエストが成功した場合にdone以下に書かれた関数が実行されます またその際、引数にはレスポンスが入ってきます。このレスポンスを活用してこのあとHTMLを書き換えていきます。
$.ajax({ 省略 }).done( function(data) { console.log(data) // <- dataにレスポンスが入っている })
HTMLを書き換える
最後にajaxで取得してきたレスポンスデータを使って TodoListを追加していけるようにHTMLを書き換えましょう!
$(document).ready(function() { $("#submit").on('click', function(e) { e.preventDefault(); var text = $('#task_title').val() $.ajax({ type: 'POST', url: '/tasks', data: { task: { title: text, } }, dataType: 'json' }).done(function(data){ $('#task-list').append( `<tr> <td> ${data.title} </td> </tr>` ) // task_listに新しいtodoデータをつかった<td>を追加 }) $('#task_title').val('') // formの値をリセット }) })
Reference
以下の記事を目に通すとよりajaxやjQueryへの理解が進みます。 とはいえ今はES6 + React/Vueなどのフレームワークの時代です。 かんたんなjQueryでDOM操作になれたあとは しっかりとJavaScriptの基礎を学び → ES6を学び → React/Vueなどのフレームワークに挑戦 もしていけるといいですね! もちろんjQueryも正しく使えばまだまだ使っていける技術だと思っています!
Ajaxについて https://qiita.com/zakiyamaaaaa/items/bdda422db2ccbaea60d9 jQueryによるDOM操作 https://qiita.com/nekoneko-wanwan/items/227ccad5f8cc449e91e9
Ruby2.5.1のObservableモジュールを写経した
場所
~/.rbenv/versions/2.5.1/lib/ruby/2.5.0/observer.rb
大きな流れ
①Subject(変更する側)からadd_observerを呼び出してConcreateObserver(変更通知を受け取る側)のObjectとインターフェイス(デフォルトは:update)を登録する ②changed(true)を呼び出し変更フラグを立てる。これがtrueでなければnotify_observersは動かない(return falseされる) ③notify_observersを呼び出し、Observerの:updateメソッドが呼ばれる
呼び出し側のコード
require 'observer' class Employee include Observable attr_reader :name, :title, :salary def initialize(name, title, salary) @name = name @title = title @salary = salary #①add_observerメソッド → Employeeの変更を通知したいObserverObjectを注入する add_observer(Payroll.new) add_observer(TaxMan.new) end def salary=(new_salary) @salary = new_salary #changed(state=true)を書くと、notify_observersが呼ばれる。 # つまり明示的に通知するかどうかを示せる changed(true) # ②observer_stateをtrueに変更する(これがfalseだとnotify_observerを呼んでも通知されない) notify_observers(self) # ③登録したObserverObjectに通知をする end end class Payroll def update(changed_employee) puts "給料あがった#{changed_employee.salary}" end end class TaxMan def update(changed_employee) puts "#{changed_employee.name} 請求書" end end john = Employee.new('John', 'Senior Vice President', 5000) john.salary = 6000
写経したObservableのコード
module Observable def add_observer(observer, func=:update) @observer_peers = {} unless defined? @observer_peers unless observer.respond_to? func raise NoMethodError, "observer does not respond to `#{func}'" end @observer_peers[observer] = func #①{ ObserverObject, :update } を配列にセットする end #.... 省略(delete_observer, count_observersなど補助的メソッド) def changed(state=true) #②変更がなされたかどうかのステータス @observer_state = state end def changed? if defined? @observer_state and @observer_state true else false end end def notify_observers(*arg) #③通知 if defined? @observer_state and @observer_state if defined? @observer_peers @observer_peers.each do |k, v| k.send v, *arg end end @observer_state = false end end end
感想
実装がとてもシンプル。初中級社のソースコードリーディングの練習に良いかも。 2.5.1のdefined便利。(nilガードとかではなく、変数やメソッドが定義されるかどうかを判別できる)
30秒でつくれるAPI Server
参照記事
公式 たった30秒でREST APIのモックが作れる JSON Serverでフロントエンド開発が捗るserver/
必要なもの
Node.js npm
手順
インストール
ターミナルにて
$ npm install -g json-server
リソースの作成
data.jsonというファイルを作成
{ "products": [ { "id": 1, "title": "少林サッカー", "price": "1200" }, { "id": 2, "title": "北野国柄", "price": "1500" } ] }
起動
ターミナルより
$ json-server --watch db.json
あとはなんでも好きにござれ
curl -X GET "http://localhost:3000/products" curl -X GET "http://localhost:3000/products/1" curl -X POST -H "Content-Type:application/json" -d '{ "id": 3, "title": "ららららららら", "price": "1000" }'
VueとかReactのajax試す時に便利だよ
便利だよ
ほかにも
sortとかoffsetぽいこととかデータ大量投入とかも簡単にできる模様 公式はこちら: https://www.npmjs.com/package/json-server
# ActiveRecordアンチパターン写経
参考記事
https://speakerdeck.com/toshimaru/active-record-anti-patterns
事例1 全Userの中から2017年以降の登録Userへ100ptを付与する。
アンチパターン① 全件取得&ループ
User.all.each do |user| if user.created_at >= Date.new(2017) user.point += 100 user.save end end
Model.allで全レコードを取得し、それにeachをかける。 →全件取得でメモリ逼迫 →ループ回数が増えCPUリソース消費
Better Way
User取得件数をフィルターして減らす all → where
少しずつUserを取得してメモリフレンドリーに each → find_each
User.where('created_at >= ?', Date.new(2017)).find_each do |user| user.point += 100 user.save end
アンチパターン② N+1 Update
# 1select User.where('created_at >= ?', Date.new(2017)).find_each do |user| user.point += 100 user.save # N update end
1回select + n回updateが走る Nの数が多くなればなるほどパフォーマンス悪化
Better Way
- 複数レコード一括更新
update -> update_all
User.where('created_at >= ?', Date.new(2017)).update_all('point = point + 100') end
実行速度爆速化!!!
※update と update_allは等価でない(callbackとか) ※テーブルロックに注意 →適切なトランザクションの設定・ロックの設定を!
事例2 ユーザー毎の記事のいいね数 合計が多い順にTOP100を出す!
アンチパターン③ Ruby Aggregation Pattern
user_like_counts = [] User.all.each do |user| user_like_counts << { name: user.name, total_like_count: user.posts.sum(&:like_count) } end user_like_counts .sort_by! { |u| u[:total_lik_count] } .reverse! .take(100).each do |u| puts "#{u[:name]} #{u[:total_like_count]}" end
Better Way
Post.group(:user_id) .select("user_id SUM(like_count) AS like_count") .order(like_count DESC) .limit(100).each do |post| puts "#{u[:name]} #{u[:total_like_count]}" end end
アンチパターン④ N+1あるでえええええ
Post.group(:user_id) .select("user_id SUM(like_count) AS like_count") .order(like_count DESC) .limit(100).each do |post| # ここやで!↓ puts "#{post.user.name} #{post.like_count]}" end end
Better Way
includesやで! joins, includes, preload, eager_loadで使い分けれるとよいね コードは省略
Rubyでデザインパターン① デザインパターン概要
参考記事
デザインパターンとは
クラスの責務分割のパターン
GoFのデザインパターン
生成
Abstract Factory Factory Method Singleton Builder Prototype
構造
Adaptor Bridge Composite Decorator Facade Flyweight Proxy
振る舞い
Command Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor
デザインパターンの効果
1. 変更容易性
2. 理解容易性
前提知識
継承
is-aの関係
コンポジション
has-aの関係 moduleとかオブジェクトの注入とか
ポリモーフィズム
問題解決の着眼点
クラスの責務分割はおおまかに3パターン
1. 変更要素の分離
アプリケーション内で固定化している部分と変動している部分をクラスとして分離する。 例1) Stateパターン: 「状態」を変動要素として切り出す 例2) Strategyパターン: 「アルゴリズム」を変動要素として切り出す
2. 間接層の道入
目的は、クラスとクラスの結合度を弱めることで 一方のクラスの変更が他方のクラスに影響を与えにくいようにすること。 例1) Proxyパターン 例2) Adaptorパターン 本来使用したい機能をもっているクラスと、それを使用するクラスの直接結合を避け、結合度を下げている。
3. 複雑さの軽減
分割をすることで、一つのクラスの責務を小さくする。 →理解容易性、変更容易性があがる