Upgrade to Pro — share decks privately, control downloads, hide ads and more …

7年目を迎えたRails アプリケーションの傾向と対策/Rails Developers Meetup 2019 Day1

taogawa
March 22, 2019

7年目を迎えたRails アプリケーションの傾向と対策/Rails Developers Meetup 2019 Day1

Rails Developers Meetup 2019でお話した「7年目を迎えたRails アプリケーションの傾向と対策」のスライドです。

taogawa

March 22, 2019
Tweet

More Decks by taogawa

Other Decks in Programming

Transcript

  1. ೥໨Λܴ͑ͨ3BJMT
    ΞϓϦέʔγϣϯͷ܏޲ͱରࡦ
    ࣦͦͯ͠ഊ
    3BJMT%FWFMPQFST.FFUVQ
    גࣜձࣾΩονϋΠΫখ઒߶

    View Slide

  2. %))৴ऀͷΈͳ͞Μ
    ͜Μʹͪ͸ʂ

    View Slide

  3. ࢲ΋Ͱ͢ʂ

    View Slide

  4. ࣗݾ঺հ
    w גࣜձࣾΩονϋΠΫΤϯδχΞ
    w খ઒߶ (JU)VCUBPHBXB

    w αʔόʔαΠυΛओʹ୲౰͍ͯ͠·͢ɻ

    View Slide

  5. %))৴ऀͱͯ͠ͷ
    Ξ΢τϓοτ

    View Slide

  6. IUUQTUFDILJUDIIJLFDPNFOUSZ

    View Slide

  7. ຊ೔ͷςʔϚ

    View Slide

  8. ຊ೔ͷςʔϚ
    Ϩʔϧ͔Βগ͠֎Εͨઌͷ
    ύλʔϯ

    View Slide

  9. ͸͡Ίʹ

    View Slide

  10. 3BJMT͸
    ʮͷιϦϡʔγϣϯͰ
    ໰୊ͷΛղܾͰ͖Δʯ
    ϑϨʔϜϫʔΫ
    ʮ3VCZPO3BJMT%))ͷΠϯλϏϡʔʯ
    IUUQTLENTOSDPNUSBOTMBUJPOTJOUFSWJFXXJUIEII ຋༁

    View Slide

  11. ͦͷͱ͓Γɺ
    େମͷ͜ͱΛ؆୯ʹ͢͹΍͘
    Ͱ͖ΔΑ͏ʹͳ͍ͬͯΔ

    View Slide

  12. ͷιϦϡʔγϣϯͰ໰୊ͷΛղܾͰ͖Δ
    w $P$ ઃఆΑΓن໿
    Ͱ൥ࡶͳઃఆϑΝΠϧΛল

    w .PEFMͱςʔϒ
    ϧͷಉҰࢹ "DUJWF3FDPSEύλʔ
    ϯ
    ͰϚοϐϯάΛγϯϓϧʹ
    w ͳͲͳͲɾɾɾ3BJMTͷ͢͹Β͠͞ͷͻͱͭ͸ɺ
    ͦͷେ୾ʹׂΓ੾ͬͨઃܭࢥ૝

    View Slide

  13. ͍ͬΆ͏ͰϨʔϧ͔Β֎ΕΔͱ͖͍ͭ
    w ్୺ʹϋʔυϧ্͕͕Δ
    w "ͦ΋ͦ΋ϨʔϧΛ͸ͣΕΔͷ͕ؒҧ͍ͬͯΔ
    w ʮͷػೳʙʯΛߟ͑Δͱਖ਼࿦
    w ͚ΕͲɺن໛͕େ͖͘ͳͬͯ͘ΔʹͭΕͯɺ΍ͬ
    ͺΓ3BJMTͷϨʔϧ͚ͩ͡Όݫ͍͠ɺͪΐͬͱ͸
    ͣΕ͍ͨέʔε͕ग़ͯ͘Δ

    View Slide

  14. ͦΜͳͱ͖Ͳ͏͢Δ͔

    View Slide

  15. ͍͔ͭ͘ͷʮϨʔϧΛͪΐͬͱ͸ͣΕͨʯ
    ఆ൪ύλʔϯ͕͋Δ
    w ංେԽͨ͠"DUJWF3FDPSEϞσϧΛϦϑΝΫλϦϯά͢
    Δͭͷํ๏
    w IUUQTUFDISBDIPCQTJODKQ
    IBDIJ@@ ຋༁

    w IUUQTDPEFDMJNBUFDPNCMPHXBZTUP
    EFDPNQPTFGBUBDUJWFSFDPSENPEFMT ݪจ

    w ೥Ҏ্લ͚ͩͲݹͼͳ͍ఆ൪ͷهࣄ

    View Slide

  16. Ͳ͔͜Ͱฉ͍ͨ͜ͱͷ͋Δύλʔϯୡ
    w 7BMVF0CKFDU
    w 4FSWJDF0CKFDU
    w 'PSN0CKFDU
    w 2VFSZ0CKFDU
    w 7JFX0CKFDU
    w 1PMJDZ0CKFDU
    w %FDPSBUPS

    View Slide

  17. Ͱ΋࣮ࡍͲ͏͔ͭ͑͹͍͍ͷ
    w ͜ΕΒͷύλʔϯͷมछΛɺ৭Μͳਓ͕গ͠
    ͣͭҧ͔ͬͨͨͪͰݴ͍ͬͯΔΑ͏ʹݟ͑Δ
    w ݁ہɺ࣮ࡍʹऔΓೖΕΔஈͰɺͲ͏࣮૷͢Δ
    ͔໎ࢠʹͳͬͯ͠·͏

    View Slide

  18. ੈͷதʹ
    ʮͪΐͬͱ͸ͣΕͨϨʔϧʯ
    ͷݱ৔Ͱͷ࣮ྫ͕
    ·ͩ·ͩදʹग़͍ͯͳ͍

    View Slide

  19. ͳΒ͹
    Φʔϓϯʹ͢Δ͔͠ͳ͍

    View Slide

  20. ࠓճ͸͜͏ͨ͠ύλʔϯΛ
    ΩονϋΠΫͰ
    Ͳ͏࢖͖͔ͬͯͨɺ
    ࣦഊ΋ؚΊͯ
    ͝঺հ͠·͢

    View Slide

  21. ࠓճ͝঺հ͢Δύλʔϯ
    w 7JFX.PEFM
    w 'PSN.PEFM
    w 4FSWJDF0CKFDU

    View Slide

  22. ͦͷ·͑ʹ

    View Slide

  23. ΩονϋΠΫͷίʔυ
    w ೥݄3BJMT͔Β։ൃελʔτ
    w ೥݄αʔϏεϩʔϯν
    w Ҏ߱਺೥ؒɺdਓ͘Β͍Ͱ։ൃ
    w ೥݄ݱࡏ
    w σβΠφʔਓ
    w ϓϩάϥϚʔਓ
    w ೥໨Λܴ͑ɺͦΕͳΓʹྺ࢙͋Δίʔυʹͳ͖ͬͯͨ

    View Slide

  24. ΩονϋΠΫͷίʔυ
    w ݱࡏͷόʔδϣϯ
    w 3VCZ ૣ্͍͛ͨ͘

    w 3BJMT ૣ্͍͛ͨ͘

    w .POHPJE
    w .POHP%#

    View Slide

  25. ΩονϋΠΫͷίʔυ
    w $POUSPMMFS
    w $MBTTFT -0$
    w .PEFMT
    w $MBTTFT -0$
    w খن໛Ͱͳ͘ͳͬͨେ͖͞

    View Slide

  26. ͦͷ
    7JFX.PEFM

    View Slide

  27. Ϣʔεέʔε
    w දࣔͷΈʹ࢖͏Α͏ͳϩδοΫ
    w ෳ਺Ϟσϧʹ·͕ͨΔදࣔϩδοΫ
    w ஔ͖৔ॴʹࠔΔͳ͜Εɾɾɾ
    w ଥڠతͳબ୒͔ΒϏϡʔʹॻ͔ΕɺϏϡʔ͕͝
    ͪΌͪ͝Όͯ͘͠Δ

    View Slide

  28. ͜Μͳͱ͖
    # 表示にだけ必要な日付フォーマット
    = @event.start_at.strftime('%Y/%m/%d %H:%M')
    # 複数のモデルが関連する表示ロジック
    - if @user.paid_member? && @product.member_only_discount?
    = @product.discount_price
    - else
    = @product.price

    View Slide

  29. ରࡦ͜͜Ͱ7JFX.PEFMͷग़൪
    w දࣔϩδοΫΛ$POUSPMMFSͰ΋ͳ͘ɺ7JFXͰ
    ΋ͳ͘ɺ7JFX.PEFMʹॻ͘
    w ͦΕ༻ͷ(FN΋͋Δ "DUJWF%FDPSBUPS΍
    %SBQFS

    w 1030Ͱ΋े෼

    View Slide

  30. 7JFX.PEFM 1SFTFOUFS
    ͷఆٛ
    class ProductPresenter
    # ...
    def price
    discount? ? @product.discount_price : @product.price
    end
    def discount?
    @user.paid_member? && @product.member_only_discount?
    end
    end

    View Slide

  31. 7JFX͕͖ͬ͢Γʂ
    # before
    - if @user.paid_member? && @product.member_only_discount?
    = @product.discount_price
    - else
    = @product.price
    - end
    # after
    = @product_presenter.price

    View Slide

  32. ͪͳΈʹ
    w ʮදࣔϩδοΫ༻ͷϞσϧʯ͸͍Ζ͍Ζͳݺ
    ͼํ͕͋Δ
    w 7JFX.PEFM 7JFX0CKFDU %FDPSBUPS
    1SFTFOUFSɾɾɾ
    w ͲΕ͕ਖ਼͍͠ͱ͍͏ͷ͸ͳ͍͕ɺνʔϜ಺Ͱೝ
    ࣝΛ߹Θ͓ͤͯ͘ͷ͕٢

    View Slide

  33. ͪͳΈʹ
    w ΩονϋΠΫͰ͸ҎԼͷΑ͏ʹݺͼ෼͚͍ͯ
    Δ
    w ૯শʮ7JFX.PEFMʯ
    w ୯ҰϞσϧ༻ʮ%FDPSBUPSʯ
    w ෳ਺Ϟσϧ༻ʮ1SFTFOUFSʯ

    View Slide

  34. Ϡολʔ
    7JFX.PEFM
    ࠷ߴ

    View Slide

  35. View Slide

  36. ͦͯ͠ɺམͱ݀͠

    View Slide

  37. ௐࢠʹ৐Γ࣮͗ͨ͢ྫ
    w ΋ͬͱԠ༻Ͱ͖ΔͷͰ͸ʁͱࢥࣦͬͯഊͨ͠
    ࣮ྫ
    w Ϩίʔυͷछྨ͝ͱʹࢀর͢ΔϞσϧ͕ҧ͏
    ͓஌ΒͤΛ࣮૷͠Α͏ͱͨ͠ͱ͖ͷ͜ͱ

    View Slide

  38. ͓஌Βͤը໘
    w ͓஌Βͤͷ৘ใ͸छྨ͝ͱ
    ʹ͍ΖΜͳςʔϒ
    ϧ͔Βσʔ
    λΛऔΔඞཁ͕͋Δ
    w ҰํɺදࣔΠϯλʔϑΣʔ
    ε͸ڞ௨
    w ͓஌Βͤ༻ςʔϒϧ࡞Βͳ
    ͯ͘΋ɺ1SFTFOUFSͰ͍͚
    ΔͷͰ͸ʁ

    View Slide

  39. Ͳ͏ͳ͔ͬͨ
    w ୺తʹݴࣦͬͯഊͩͬͨ
    w /໰୊͕ൃੜɻ͔͠΋ɺߏ଄తʹ௚ͮ͠Β͍
    w ࢀর͢Δςʔϒϧ͕Ϩίʔυ͝ͱʹҧ͏͔Β
    FBHFS@MPBEͮ͠Β͍
    w ૉ௚ʹςʔϒϧ࡞Ε͹Α͔ͬͨͷʹɾɾɾ

    View Slide

  40. 7JFX.PEFMͷֶͼ
    w 7JFX.PEFM͸1030ͳͷͰ৭ʑ༥௨͕ར͖΍
    ͍͢
    w ͕ͩɺ.PEFM͔Βੜ੒͢ΔͷͰɺσʔλΞΫη
    εͷ໰୊͕ى͖΍͍͢
    w ಛʹҰཡܥͰ͸ཁ஫ҙ

    View Slide

  41. ͦͷ
    'PSN.PEFM

    View Slide

  42. Ϣʔεέʔε
    w Ϟσϧʹඥ෇͔ͳ͍ϑΥʔϜΛѻ͏έʔε
    w ӬଓԽ͠ͳ͍߲໨͕͋Δ
    w ෳ਺Ϟσϧʹ·͕ͨΔ
    w ϦΫΤετύϥϝʔλΛ$POUSPMMFS಺Ͱ͋͋ͨ͠Γɺ
    ͜͏ͨ͠Γɾɾɾ
    w $POUSPMMFS಺ͷίʔυ͕ͪ͝Όͪ͝Όͯ͘͠Δ

    View Slide

  43. Α͋͘Δ֬ೝνΣοΫ
    w ϝοηʔδ͸%#ʹ
    อଘͷඞཁ͕͋Δ͕ɺ
    ֬ೝνΣοΫ͸อଘ
    ෆཁ

    View Slide

  44. Α͋͘Δ֬ೝνΣοΫ
    # view
    = form_for(@event, url:foo_path(@event), method: 'patch') do |f|
    = f.hidden_field :event_id
    = text_area_tag :body
    = check_box_tag :confirmed # 確認チェック
    = f.submit "予約をキャンセル"
    # controller
    # パラメータのチェックが複数あると見通しが悪くなる
    if params[:confirmed] == "1"
    # ...
    else
    # ...
    end

    View Slide

  45. ରࡦ͜͜Ͱ'PSN.PEFMͷग़൪
    w Ϟσϧʹඥ෇͔ͳ͍ɺϑΥʔϜઐ༻ͷϞσϧΛ
    ఆٛ͢Δ
    w ϦΫΤετύϥϝʔλͷνΣοΫͳͲ͸'PSN
    .PEFM಺Ͱߦ͏

    View Slide

  46. 'PSN.PEFMͷఆٛ
    class EventCancellationMessageForm
    include ActiveModel::Model
    attr_accessor :event_id, :body, :confirmed
    validates :body, presence: true
    validates :confirmed, acceptance: true
    # ...
    end

    View Slide

  47. $POUSPMMFS͕͖ͬ͢Γʂ
    # before
    if params[:confirmed] == "1"
    # ...
    else
    # ...
    end
    # after
    @event_cancellation_form =
    EventCancellationMessageForm.new(cancellation_message_params)
    # パラメータチェックが複数あってもFormModel内で処理できる
    if @event_cancellation_form.valid?
    # ...
    end

    View Slide

  48. 'PSN.PEFMͷఆٛ
    w "DUJWF.PEFM.PEFMΛJODMVEF
    w GPSN@XJUI GPSN@GPSͰ௨ৗͷϞσϧͷΑ͏ʹѻ͑Δʂ
    w ϑΥʔϜʹඥ෇͔ͳ͍όϦσʔγϣϯΛ'PSN.PEFM
    ಺Ͱ͖ͬ͢Γॻ͚Δ
    w ʮ֬ೝ͠·ͨ͠ʯνΣοΫ
    w ෳ਺Ϟσϧʹ·͕ͨΔόϦσʔγϣϯ

    View Slide

  49. ͞ΒʹɺԠ༻΋ར͘ΜͰ͢
    # view
    = form_for @bulk_schedule_form, url:schedules_path, method: "post" do |f|
    = f.fields_for :schedules do |s|
    # ...
    =f.submit "一括登録"
    # form_model
    class BulkScheduleForm
    includes Activemodel::Model
    attr_accessor: schedules
    # ...
    def schedule_attributes=(attributes)
    self.schedules = attributes.map do |schedule_attributes|
    schedule.new(schedule_attributes)
    end
    end
    end

    View Slide

  50. Ұׅొ࿥'PSNʹ΋࢖͑Δ
    w গ͠खΛՃ͑Ε͹Ұׅొ࿥'PSNͳͲʹ΋Ԡ༻
    ͕ར͘
    w ࢠϨίʔυͷߋ৽΋ؚΉ৔߹ɺ
    BDDFQUT@OFTUFE@BUUSJCVUFT@GPS΋ͳͤ͘Δ

    View Slide

  51. Ϡολʔ
    'PSN.PEFM
    ࠷ߴ

    View Slide

  52. View Slide

  53. ͦͯ͠ɺམͱ݀͠

    View Slide

  54. 'PSN.PEFMଠΓ͕ͪ໰୊
    w 'PSN.PEFM͕ଠͬͯ͠·ͬͨ
    w όϦσʔγϣϯ͕ෳࡶԽ
    w ͜Ε͸Ϟσϧʹॻ͚͹͍͍ͷͰ͸ʁͳόϦσʔ
    γϣϯ·Ͱ'PSN.PEFMʹॻ͔Εͯ͠·ͬͨ

    View Slide

  55. 'PSN.PEFMͷֶͼ
    w 'PSN.PEFM͸Ԡ༻΋ར͍ͯ΂ΜΓ
    w 'PSN.PEFM͸ബ͘ɻ͋͘·Ͱओ໾͸.PEFM
    w όϦσʔγϣϯͳͲͷ੹຿͸ɺ.PEFMʹۃྗ࣋
    ͨͤͯɺ'PSN.PEFM͸ͦΕΛݺͼग़͚ͩ͢ʹ
    ͠Α͏

    View Slide

  56. ͦͷ
    4FSWJDF0CKFDU

    View Slide

  57. Ϣʔεέʔε
    w ͋Δखଓ͖Λͻͱ·ͱ·Γʹ͍ͨ͠ͱ͖
    w ෳ਺ͷϞσϧʹର͢Δॲཧ
    w %#ͷτϥϯβΫγϣϯ
    w ϕλʹ$POUSPMMFSʹॻ͍͍ͯͬͯɺ$POUSPMMFS
    ͷݟ௨͕͠ѱ͘ͳΔ

    View Slide

  58. ରࡦ͜͜Ͱ4FSWJDF0CKFDUͷग़൪
    w 4FSWJDF0CKFDUʹͻͱ·ͱ·ΓͷॲཧΛҠಈ͞
    ͤΔ
    w BQQTFSWJDFTҎԼʹ4FSWJDF0CKFDUΛఆٛ
    w ݴޠ໰Θͣఆ൪ͷύλʔϯ

    View Slide

  59. 4FSWJDF0CKFDUͷఆٛ
    # service_object
    class EventCreateService
    def initialize(params)
    # ...
    end
    def call
    # ...
    end
    end
    # controller
    service = EventCreateService.new(event_params)
    service.call
    if service.success?
    # ...
    end

    View Slide

  60. 4FSWJDF0CKFDUͷఆٛ
    w ίϯετϥΫλҎ֎ɺQVCMJDϝιου͸جຊͻͱͭͷΈ
    w DBMMͱ͔FYFDVUFͱ͔
    w $PNNBOEύλʔϯͬΆ͍
    w ඞཁʹԠͯ͡εςʔτϦʔμʔΛఆٛ
    w $POUSPMMFSʹϕλॻ͖͞ΕͨϏδωεϩδοΫΛ
    4FSWJDF0CKFDUʹఆٛͯ͠ɺ$POUSPMMFSΛ͖ͬ͢Γ

    View Slide

  61. 4FSWJDF0CKFDUͷఆٛ
    w ϝδϟʔͳύλʔϯͳͷͰɺ044΋ࢀߟʹ͠΍͍͢
    w .BTUPEPOͳͲ
    w ΩονϋΠΫͰ͸ҎԼΛࢀߟʹ͍ͯ͠Δ
    w 3BJMTͰॏཁͳύλʔϯQBSU4FSWJDF0CKFDU
    w IUUQTUFDISBDIPCQTJODKQ
    IBDIJ@@ ຋༁

    View Slide

  62. Ϡολʔ
    4FSWJDF0CKFDU
    ࠷ߴ

    View Slide

  63. View Slide

  64. ͦͯ͠ɺམͱ݀͠

    View Slide

  65. αʔϏεͷ֓೦޿͗͢໰୊
    w 4FSWJDFͷޠ͕Ұൠత͗ͯ͢ɺ͍ΖΜͳఆ͕ٛ
    ͋Δ
    w ΈΜͳͷ;Θͬͱͨ͠ײ֮ͰΫϥεΛ௥Ճ͠
    ͍ͯ͘ͱɺBQQTFSWJDFTσ
    ΟϨΫτϦҎԼ͕ଠͬ
    ͍ͯ͘

    View Slide

  66. ͋ͳͨͷαʔϏε͸ͲͷαʔϏεʁ
    w ͦ΋ͦ΋&SJD&WBOTͷ%%%ຊͰͷαʔϏεఆ͕ٛ෯޿͍
    w ΞϓϦέʔγϣϯαʔϏε
    w υϝΠϯαʔϏε
    w ΠϯϑϥετϥΫνϟαʔϏε
    w 1PG&""ͷαʔϏεϨΠϠʔ
    w ͍͍ײ͡ͷศརϝιουͱͯ͠4FSWJDF͕࢖ΘΕΔ
    w ͜ͷ఺Λҙ͍ࣝͯ͠ͳ͍ͱɺ࿩͕͔Έ߹Θͳ͍

    View Slide

  67. ͞Βʹɺམͱ݀͠

    View Slide

  68. τϥϯβΫγϣϯεΫϦϓτ໰୊
    w 4FSWJDF0CKFDUʹϞϦϞϦϩδοΫΛॻ͍ͯ͠
    ·͏
    w ݁Ռɺ$POUSPMMFSͷ͔ΘΓʹ4FSWJDF0CKFDU
    ͷݟ௨͕͠ѱ͍͚ͩʹͳΔ
    w υϝΠϯϞσϧශ݂঱

    View Slide

  69. ֓೦Λ੔ཧ͢Δ
    w ΩονϋΠΫͰͷαʔϏε͸ΞϓϦέʔγϣ
    ϯαʔϏεͱͯ͠ఆ͍ٛͯ͠Δ
    w ͱ͸͍͏΋ͷͷɺ৭ʑͳαʔϏε͕ࠞࡏͯ͠
    ͍ͯಓ൒͹

    View Slide

  70. αʔϏε͸ബ͘
    w ϩδοΫ͸Ϟσϧʹॻ͘
    w 4FSWJDF0CKFDU͸ͦΕΛݺͼग़͚ͩ͢
    w αʔϏεΫϥεʹͭͷ࢓ࣄ
    w ಈࢺ໊ࢺ4FSWJDF
    w ྫ$SFBUF&WFOU4FSWJDF

    View Slide

  71. 4FSWJDF0CKFDUͷֶͼ
    w 4FSWJDFͷڞ௨ೝࣝΛνʔϜ಺Ͱڞ༗͓ͯ͘͠
    w ڞ௨ͨ͠ਖ਼ղͱ͍͏΋ͷ͸ͳͦ͞͏
    w ஔ͖৔΍໋໊نଇɺΠϯλʔϑΣʔεΛͪΌΜͱ੔උ
    ͠Α͏
    w 4FSWJDF͸ബ͘ɻ͋͘·Ͱओ໾͸.PEFM
    w υϝΠϯϩδοΫ͸ɺ.PEFMʹۃྗ࣋ͨͤͯɺ4FSWJDF
    0CKFDU͸ͦΕΛݺͼग़͚ͩ͢ʹ͠Α͏

    View Slide

  72. ·ͱΊ

    View Slide

  73. ϨʔϧΛͪΐͬͱ֎Εͨ
    ఆ൪ύλʔϯͨͪɺ
    ศརͰ͢Α

    View Slide

  74. ͚ΕͲ
    ੈͷதʹ͸·ͩ·࣮ͩྫ͕଍Γͳ͍
    ݱ৔ͷ஌ݟ͕޿·Βͳ͚Ε͹
    ύλʔϯ͸ఆண͠ͳ͍

    View Slide

  75. ͜ΕͰ3BJMT͸
    େ͖ͳΞϓϦέʔγϣϯʹ࢖͑ͳ͍
    ͳΜͯݴ༿͸ෆຊҙͰ͸ʁ

    View Slide

  76. ΋ͬͱ΋ͬͱ
    ࣗ෼ͨͪͷ
    औΓ૊ΈΛɺࣦഊΛɺ
    Φʔϓϯʹ͢Δ
    ͦΜͳ3BJMTίϛϡχςΟ΁ͷ
    ߩݙ΋͋ΔͷͰ͸

    View Slide

  77. ΋ͬͱ΋ͬͱ
    Έͳ͞Μͷ
    ݱ৔ͷ஌ݟΛΦʔϓϯʹ

    View Slide

  78. ͝ਗ਼ௌ
    ͋Γ͕ͱ͏͍͟͝·ͨ͠

    View Slide