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

How to write good code.

How to write good code.

My presentation at VarnaConf.
Code from the presentation: https://github.com/RStankov/varna-conf-2012
Video from the presentation: https://www.youtube.com/watch?v=avhljVTlHZE

Radoslav Stankov

August 11, 2012
Tweet

More Decks by Radoslav Stankov

Other Decks in Technology

Transcript

  1. Radoslav Stankov
    VarnaConf 11/08/2012
    How to write good code

    View full-size slide

  2. How am I?
    @rstankov
    http://rstankov.com
    http://github.com/rstankov

    View full-size slide

  3. Huey Dewey Louie

    View full-size slide



  4. Section 1

    ...
    ...
    ...



    View full-size slide

  5. $('.accordion-menu .item a').each(function() {
    $(this).bind('click', function() {
    var title = this.className;
    var theul = $('#' + title);
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    } else {
    }
    });
    });

    View full-size slide

  6. $('.accordion-menu .item a').each(function() {
    $(this).bind('click', function() {
    var title = this.className;
    var theul = $('#' + title);
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    } else {
    }
    });
    });

    View full-size slide

  7. $('.accordion-menu .item a').each(function() {
    $(this).bind('click', function() {
    var title = this.className;
    var theul = $('#' + title);
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    }
    });
    });

    View full-size slide

  8. $('.accordion-menu .item a').each(function() {
    $(this).bind('click', function() {
    var title = this.className;
    var theul = $('#' + title);
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    }
    });
    });

    View full-size slide

  9. $('.accordion-menu .item a').click(function() {
    var title = this.className;
    var theul = $('#' + title);
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    }
    });

    View full-size slide

  10. $('.accordion-menu .item a').click(function() {
    var title = this.className;
    var theul = $('#' + title);
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    }
    });

    View full-size slide



  11. Section 1

    ...
    ...
    ...



    View full-size slide



  12. Section 1

    ...
    ...
    ...



    View full-size slide



  13. Section 1

    ...
    ...
    ...



    View full-size slide



  14. Section 1

    ...
    ...
    ...



    View full-size slide



  15. Section 1

    ...
    ...
    ...



    View full-size slide

  16. $('.accordion-menu .item a').click(function() {
    var title = this.className;
    var theul = $('#' + title);
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    }
    });

    View full-size slide

  17. $('.accordion-menu .item a').click(function() {
    var title = this.className;
    var theul = $('#' + title);
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    }
    });

    View full-size slide

  18. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul');
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    }
    });

    View full-size slide

  19. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul');
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    }
    });

    View full-size slide

  20. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul');
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    } else {
    theul.slideUp();
    var theli = dropa.parent('li');
    theli.animate({'padding-bottom': '20px'});
    }
    }
    });

    View full-size slide

  21. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul');
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown()
    } else {
    theul.slideUp()
    }
    var theli = dropa.parent('li')
    theli.animate({'padding-bottom': '20px'});
    }
    });

    View full-size slide

  22. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul');
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown()
    } else {
    theul.slideUp()
    }
    var theli = dropa.parent('li')
    theli.animate({'padding-bottom': '20px'});
    }
    });

    View full-size slide

  23. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul')
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown()
    } else {
    theul.slideUp()
    }
    }
    });

    View full-size slide

  24. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul')
    if (theul.length > 0) {
    if (theul.css('display') == 'none') {
    theul.slideDown()
    } else {
    theul.slideUp()
    }
    }
    });

    View full-size slide

  25. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul')
    if (theul.length > 0) {
    if (theul.is(':visible')) {
    theul.slideDown()
    } else {
    theul.slideUp()
    }
    }
    });

    View full-size slide

  26. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul')
    if (theul.length > 0) {
    if (theul.is(':visible')) {
    theul.slideDown()
    } else {
    theul.slideUp()
    }
    }
    });

    View full-size slide

  27. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul')
    if (theul.length > 0) {
    if (theul.is(':visible')) {
    theul.slideDown()
    } else {
    theul.slideUp()
    }
    }
    });

    View full-size slide

  28. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul')
    if (theul.length > 0) {
    theul.slideToggle();
    }
    });

    View full-size slide

  29. $('.accordion-menu .item a').click(function() {
    var theul = $(this).next('ul')
    if (theul.length > 0) {
    theul.slideToggle();
    }
    });

    View full-size slide

  30. $('.accordion-menu .item a').click(function() {
    $(this).next('ul').slideToggle();
    });

    View full-size slide

  31. $('.accordion-menu .item a').click(function() {
    $(this).next('ul').slideToggle();
    });

    View full-size slide

  32. $('.accordion-menu .item a').click(function() {
    $(this).next('ul').slideToggle();
    });

    View full-size slide

  33. $('.accordion-menu .item a').live('click', function() {
    $(this).next('ul').slideToggle();
    });

    View full-size slide

  34. $('.accordion-menu .item a').live('click', function() {
    $(this).next('ul').slideToggle();
    });

    View full-size slide

  35. $('.accordion-menu .item a').live('click', function() {
    $(this).next('ul').slideToggle();
    });

    View full-size slide

  36. $('.accordion-menu .item a').click(function() {
    $(this).next('ul').slideToggle();
    });

    View full-size slide

  37. $(document).on('click', '.accordion-menu .item a', function() {
    $(this).next('ul').slideToggle();
    });

    View full-size slide

  38. $(document).on('click', '.js-accordion-item a', function() {
    $(this).next('js-accordion-section').slideToggle();
    });

    View full-size slide

  39. $(document).on('click', '[data-accordion="item"]', function() {
    $(this).next('[data-accordion="section"]').slideToggle();
    });

    View full-size slide

  40. Know your tools

    View full-size slide

  41. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  42. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  43. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  44. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  45. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  46. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  47. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  48. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  49. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  50. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  51. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])
    Copy
    &
    Paste

    View full-size slide

  52. class MostLikedFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('votes_count')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    MostLikedFriendImages.new(current_user).images(params[:page])

    View full-size slide

  53. class MostLikedFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('votes_count')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    MostLikedFriendImages.new(current_user).images(params[:page])

    View full-size slide

  54. class MostLikedFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('votes_count')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    MostLikedFriendImages.new(current_user).images(params[:page])

    View full-size slide

  55. class MostLikedFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('votes_count')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    MostLikedFriendImages.new(current_user).images(params[:page])

    View full-size slide

  56. class MostLikedFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('votes_count')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    MostLikedFriendImages.new(current_user).images(params[:page])

    View full-size slide

  57. DRY
    don’t repeat yourself

    View full-size slide

  58. Every piece of knowledge must have
    a single, unambiguous, authoritative
    representation within a system.

    View full-size slide

  59. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  60. class NewsestFriendImages
    def initialize(user)
    @user = user
    end
    def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    NewsestFriendImages.new(current_user).images(params[:page])

    View full-size slide

  61. class FriendImages
    def initialize(user)
    @user = user
    end
    def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    FriendImages.new(current_user).images('created_at', params[:page])
    FriendImages.new(current_user).images('likes_count', params[:page])

    View full-size slide

  62. class FriendImages
    def initialize(user)
    @user = user
    end
    def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    FriendImages.new(current_user).images('created_at', params[:page])
    FriendImages.new(current_user).images('likes_count', params[:page])

    View full-size slide

  63. class FriendImages
    def initialize(user)
    @user = user
    end
    def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    FriendImages.new(current_user).images('created_at', params[:page])
    FriendImages.new(current_user).images('likes_count', params[:page])

    View full-size slide

  64. class FriendImages
    def initialize(user)
    @user = user
    end
    def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    FriendImages.new(current_user).images('created_at', params[:page])
    FriendImages.new(current_user).images('likes_count', params[:page])

    View full-size slide

  65. class FriendImages
    def initialize(user)
    @user = user
    end
    def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    FriendImages.new(current_user).images('created_at', params[:page])
    FriendImages.new(current_user).images('likes_count', params[:page])

    View full-size slide

  66. class FriendImages
    def initialize(user)
    @user = user
    end
    def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    FriendImages.new(current_user).images('created_at', params[:page])
    FriendImages.new(current_user).images('likes_count', params[:page])

    View full-size slide

  67. class FriendImages
    def initialize(user)
    @user = user
    end
    def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end
    FriendImages.new(current_user).images('created_at', params[:page])
    FriendImages.new(current_user).images('likes_count', params[:page])

    View full-size slide

  68. The bad side of DRY

    View full-size slide

  69. http://bit.ly/O5jSLV

    View full-size slide

  70. API_GET = '/api/:source_type/:id'
    API_GET_DETAILS = '/api/:source_type/:id/details'
    API_GET_VERSION = '/api/:source_type/:id/on/:year/:date/:month'
    API_GET_SUBTYPE = '/api/:source_type/:id/sub/:subtype/:subtype_id'

    View full-size slide

  71. API = 'api'
    SOURCE_TYPE = '/:source_type'
    SOURCE_ID = '/:id'
    SOURCE_DATE = '/:year/:month/:day'
    SUBTYPE = '/:subtype'
    SUBID = '/:subtype_id'
    API_GET = API + SOURCE_TYPE + SOURCE_ID
    API_GET_DETAILS = API + SOURCE_TYPE + SOURCE_ID + '/details'
    API_GET_VERSION = API + SOURCE_TYPE + SOURCE_ID + '/on' + SOURCE_DATE
    API_GET_SUBTYPE = API + SOURCE_TYPE + SOURCE_ID + '/sub' + SUBTYPE + SUBID

    View full-size slide

  72. def api_path(rest = '')
    BASE_PATH + rest
    end
    def token(string)
    SEPARATOR + string
    end
    SEPARATOR = '/'
    API = 'api'
    SOURCE_TYPE = ':source_type'
    SOURCE_ID = ':id'
    YEAR = ':year'
    MONTH = ':month'
    DAY = ':day'
    SUBTYPE = ':subtype'
    SUBID = ':subtype_id'
    DETAILS = 'details'
    ON = 'on'
    SUB = 'sub'
    BASE_PATH = token(API) + token(SOURCE_TYPE) + token(SOURCE_ID)
    DATE_PART = token(YEAR) + token(MONTH) + token(DAY)
    SUB_PART = token(SUBTYPE) + token(SUBID)
    API_GET = api_path()
    API_GET_DETAILS = api_path(token(DETAILS))
    API_GET_VERSION = api_path(token(ON) + token(DATE_PART))
    API_GET_SUBTYPE = api_path(token(SUB) + token(SUB_PART))

    View full-size slide

  73. class FriendImages
    def initialize(user)
    @user = user
    end
    def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end

    View full-size slide

  74. SLAP
    Single Level of Abstraction Principle

    View full-size slide

  75. Keep all lines of code in a method at
    the same level of abstraction.

    View full-size slide

  76. class FriendImages
    def initialize(user)
    @user = user
    end
    def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end
    end

    View full-size slide

  77. def images(sorting, page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order(sorting)
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end

    View full-size slide

  78. def images(sorting, page)
    images = find_images_of(friends)
    images = apply_age_restritions_to(images)
    images = order_by(images, sorting)
    images = paginate(images, page)
    decorate(images)
    end

    View full-size slide

  79. def friends
    Friendship.where(user_id: @user.id).pluck('friend_id')
    end
    def find_images_of(friends)
    Image.where(user_id: friends, visible_to_friends: true)
    end
    def apply_age_restritions_to(images)
    images.where('minimum_age >= ?', @user.age)
    end
    def order_by(sorting)
    images.order(sorting)
    end
    def paginate(page)
    images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    end
    def decorate(images)
    images.map { |image| ImageDecorator.new(image) }
    end

    View full-size slide

  80. Law of Demeter

    View full-size slide

  81. • You can play with yourself.
    • You can play with your own toys (but you can't
    take them apart),
    • You can play with toys that were given to you.
    • And you can play with toys you've made
    yourself.

    View full-size slide

  82. • Your method can call other methods in its
    class directly
    • Your method can call methods on its own
    fields directly (but not on the fields' fields)
    • When your method takes parameters, your
    method can call methods on those parameters
    directly.
    • When your method creates local objects, that
    method can call methods on the local objects.

    View full-size slide

  83. def friends
    Friendship.where(user_id: @user.id).pluck('friend_id')
    end
    def find_images_of(friends)
    Image.where(user_id: friends, visible_to_friends: true)
    end
    def apply_age_restritions_to(images)
    images.where('minimum_age >= ?', @user.age)
    end
    def order_by(sorting)
    images.order(sorting)
    end
    def paginate(page)
    images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    end
    def decorate(images)
    images.map { |image| ImageDecorator.new(image) }
    end

    View full-size slide

  84. def friends
    Friendship.friend_ids_of(@user)
    end
    def find_images_of(friends)
    Image.of(friends)
    end
    def apply_age_restritions_to(images)
    images.appropriate_for(@user.age)
    end
    def order_by(sorting)
    images.order(sorting)
    end
    def paginate(page)
    images.paginate(page)
    end
    def decorate(images)
    images.map { |image| ImageDecorator.new(image) }
    end

    View full-size slide

  85. def images(sorting, page)
    images = find_images_of(friends)
    images = apply_age_restritions_to(images)
    images = order_by(images, sorting)
    images = paginate(images, page)
    decorate(images)
    end

    View full-size slide

  86. def images(sorting, page)
    decorate Image
    .of(friends)
    .appropriate_for(@user.age)
    .order(sorting)
    .paginate(page)
    end

    View full-size slide

  87. def images(page)
    friends = Friendship.where(user_id: @user.id).pluck('friend_id')
    images = Image.where(user_id: friends, visible_to_friends: true)
    images = images.where('minimum_age >= ?', @user.age)
    images = images.order('created_at')
    images = images.limit(PER_PAGE).offset(page.to_i.abs * PER_PAGE)
    images.map { |image| ImageDecorator.new(image) }
    end

    View full-size slide

  88. def images(sorting, page)
    decorate Image
    .of(friends)
    .appropriate_for(@user.age)
    .order(sorting)
    .paginate(page)
    end

    View full-size slide

  89. • Duplicated Code
    • Long Method
    • Large Class
    • Long Parameter List
    • Shotgun Surgery
    • Feature Envy
    • Data Clumps
    • Case Statements
    • Parallel Inheritance Hierarchies
    • Speculative Generality
    • Temporary Field
    • Message Chains
    • Middle Man
    • Alternative Classes with Different Interfaces
    • Refused Bequest
    • Comments
    • Repetitive Boilerplate
    • и т.н....

    View full-size slide

  90. Refactoring:
    Improving the Design of Existing Code.
    Martin Fowler

    View full-size slide

  91. Out side of the box

    View full-size slide

  92. Retrospection

    View full-size slide

  93. Retrospection
    ✓ DRY

    View full-size slide

  94. Retrospection
    ✓ DRY
    ✓ SLAP

    View full-size slide

  95. Retrospection
    ✓ DRY
    ✓ SLAP
    ✓ Law of demeter

    View full-size slide

  96. Retrospection
    ✓ DRY
    ✓ SLAP
    ✓ Law of demeter
    ✓ Tools

    View full-size slide

  97. Retrospection
    ✓ DRY
    ✓ SLAP
    ✓ Law of demeter
    ✓ Tools
    ✓ Code smells

    View full-size slide

  98. Retrospection
    ✓ DRY
    ✓ SLAP
    ✓ Law of demeter
    ✓ Tools
    ✓ Code smells
    ✓ Out side the box

    View full-size slide

  99. Code, step by step
    https://github.com/RStankov/varna-conf-2012

    View full-size slide

  100. @rstankov
    Thanks for listening :)

    View full-size slide