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

Eliminating Noice from your Code

Eliminating Noice from your Code

Radoslav Stankov

November 19, 2019
Tweet

More Decks by Radoslav Stankov

Other Decks in Technology

Transcript

  1. Radoslav Stankov 23/11/2019
    Eliminating noise
    from your
    code

    View Slide

  2. View Slide

  3. Radoslav Stankov
    @rstankov

    blog.rstankov.com

    github.com/rstankov

    twitter.com/rstankov

    View Slide

  4. View Slide

  5. View Slide

  6. https://speakerdeck.com/rstankov

    View Slide

  7. View Slide

  8. View Slide

  9. Huey

    View Slide

  10. Huey Dewey

    View Slide

  11. Huey Dewey Louie

    View Slide

  12. View Slide

  13. View Slide

  14. View Slide

  15. View Slide

  16. View Slide

  17. View Slide

  18. View Slide

  19. View Slide

  20. View Slide

  21. View Slide

  22. View Slide

  23. View Slide

  24. View Slide

  25. Why code gets bad
    overtime? !

    View Slide

  26. What is a good
    code? "

    View Slide

  27. View Slide

  28. View Slide



  29. Section 1


    ...

    ...

    ...




    View Slide

  30. $('.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 Slide

  31. $('.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 Slide

  32. #

    View Slide

  33. Is this good code? $

    View Slide

  34. Why not? %

    View Slide

  35. View Slide

  36. ... too much
    information density

    View Slide

  37. ... too much
    information noise &

    View Slide

  38. “In cognitive psychology, cognitive load refers
    to the used amount of working
    memory resources. ”
    - WikipediA
    Cognitive load

    View Slide

  39. “Ego depletion refers to the idea that self-
    control or willpower draws upon a limited pool
    of mental resources that can be used up.”
    - WikipediA
    Ego depletion

    View Slide

  40. View Slide

  41. View Slide

  42. View Slide

  43. View Slide

  44. View Slide

  45. View Slide

  46. $('.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 Slide

  47. $('.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 Slide

  48. $('.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 Slide

  49. $('.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 Slide

  50. $('.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 Slide

  51. $('.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 Slide



  52. Section 1


    ...

    ...

    ...




    View Slide



  53. Section 1


    ...

    ...

    ...




    View Slide



  54. Section 1


    ...

    ...

    ...




    View Slide



  55. Section 1


    ...

    ...

    ...




    View Slide



  56. Section 1


    ...

    ...

    ...




    View Slide

  57. $('.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 Slide

  58. $('.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 Slide

  59. $('.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 Slide

  60. $('.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 Slide

  61. $('.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 Slide

  62. $('.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 Slide

  63. $('.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 Slide

  64. $('.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 Slide

  65. $('.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 Slide

  66. $('.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 Slide

  67. $('.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 Slide

  68. $('.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 Slide

  69. $('.accordion-menu .item a').click(function() {

    var theul = $(this).next('ul')

    if (theul.length > 0) {

    theul.slideToggle();

    }

    });

    View Slide

  70. $('.accordion-menu .item a').click(function() {

    var theul = $(this).next('ul')

    if (theul.length > 0) {

    theul.slideToggle();

    }

    });

    View Slide

  71. $('.accordion-menu .item a').click(function() {

    $(this).next('ul').slideToggle();

    });


    View Slide

  72. $('.accordion-menu .item a').click(function() {

    $(this).next('ul').slideToggle();

    });


    View Slide

  73. $('.accordion-menu .item a').click(function() {

    $(this).next('ul').slideToggle();

    });


    View Slide

  74. $('.accordion-menu .item a').live('click', function() {

    $(this).next('ul').slideToggle();

    });

    View Slide

  75. $('.accordion-menu .item a').live('click', function() {

    $(this).next('ul').slideToggle();

    });

    View Slide

  76. $('.accordion-menu .item a').live('click', function() {

    $(this).next('ul').slideToggle();

    });

    View Slide

  77. $('.accordion-menu .item a').click(function() {

    $(this).next('ul').slideToggle();

    });


    View Slide

  78. $(document).on('click', '.accordion-menu .item a', function() {

    $(this).next('ul').slideToggle();

    });


    View Slide

  79. $(document).on('click', '.js-accordion-item a', function() {

    $(this).next('js-accordion-section').slideToggle();

    });

    View Slide

  80. $(document).on('click', '[data-accordion="item"]', function() {

    $(this).next('[data-accordion="section"]').slideToggle();

    });

    View Slide

  81. View Slide

  82. View Slide

  83. View Slide

  84. View Slide

  85. “It is better to be a good programmer with great
    habits, than a great programmer.”
    - Kent Beck

    View Slide

  86. Broken windows theory

    View Slide

  87. “Social psychologists and police officers tend
    to agree that if a window in a building is
    broken and is left unrepaired, all the rest of the
    windows will soon be broken.”
    - WikipediA
    Broken windows theory

    View Slide

  88. The Boy Scout Rule

    View Slide

  89. “Leave your code better than you found it.”
    The Boy Scout Rule

    View Slide

  90. Radoslav Stankov 05/05/2018
    Eliminating noise
    from your
    code

    View Slide

  91. Radoslav Stankov 05/05/2018
    Eliminating
    ' Code Smells '

    View Slide

  92. View Slide

  93. Code smell is any symptom in the source code of a
    program that possibly indicates a deeper problem.
    Code smells

    View Slide

  94. Code smells are usually not bugs—they are not
    technically incorrect and don't currently prevent
    the program from functioning. Instead, they
    indicate weaknesses in design that may be slowing
    down development or increasing the risk of bugs
    or failures in the future.
    Code smells

    View Slide

  95. Code refactoring is a disciplined technique for
    restructuring an existing body of code, altering its
    internal structure without changing its external
    behavior
    Refactoring

    View Slide

  96. View Slide

  97. View Slide

  98. Refactoring

    View Slide

  99. #1
    Useless Code

    View Slide

  100. function LoadMoreBaseOnDevice(props) {
    return (
    <>






    >
    );
    }

    View Slide

  101. function LoadMoreBaseOnDevice(props) {
    return (

    {isMobile =>
    isMobile ? (

    ) : (

    )
    }

    );
    }

    View Slide

  102. function LoadMoreBaseOnDevice(props) {
    const isMobile = useIsMobile();
    return isMobile ? (

    ) : (

    );
    }

    View Slide

  103. click(event)} />

    View Slide

  104. click(event)} />

    View Slide


  105. View Slide

  106. function Component({ array }) {
    return (

    {array && array.length > 0 && array.map(item => )}

    );
    }

    View Slide

  107. function Component({ array }) {
    return (

    {array && array.length > 0 && array.map(item => )}

    );
    }

    View Slide

  108. function Component({ array }) {
    return (

    {array && array.map(item => )}

    );
    }

    View Slide

  109. function Component({ array }) {
    return (

    {array.map(item => )}

    );
    }

    View Slide

  110. function Component({ array }) {
    return (

    {array.map(item => )}

    );
    }

    View Slide

  111. function Component({ array }) {
    return array.map(item => );
    }

    View Slide


  112. {(variant, complete) => {
    return variant == 'left' ? (
    viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.leftForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    )
    ) : viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.topForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    );
    }}

    View Slide


  113. {(variant, complete) => {
    return variant == 'left' ? (
    viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.leftForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    )
    ) : viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.topForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    );
    }}

    View Slide


  114. {(variant, complete) =>
    variant == 'left' ? (
    viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.leftForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    )
    ) : viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.topForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    )
    }
    ;

    View Slide

  115. #2
    Too Much Conditional Logic

    View Slide

  116. View Slide

  117. View Slide


  118. {(variant, complete) =>
    variant == 'left' ? (
    viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.leftForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    )
    ) : viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.topForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    )
    }
    ;

    View Slide


  119. {(variant, complete) =>
    variant == 'left' ? (
    viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.leftForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    )
    ) : viewer ? (
    !viewer.isSubscribedToNewsletter && (
    email={viewer.email}
    className={style.topForm}
    contentClassName={styles.hideField}
    onSubscribe={complete}
    />
    )
    ) : (

    )
    }
    ;

    View Slide


  120. {(variant, complete) =>
    variant == 'left' ? (
    className={styles.leftForm}
    onSubscribe={complete}
    viewer={viewer}
    />
    ) : (
    className={style.topForm}
    onSubscribe={complete}
    viewer={viewer}
    />
    )
    }

    View Slide


  121. {(variant, complete) =>
    variant == 'left' ? (
    className={styles.leftForm}
    onSubscribe={complete}
    viewer={viewer}
    />
    ) : (
    className={style.topForm}
    onSubscribe={complete}
    viewer={viewer}
    />
    )
    }

    View Slide


  122. {(variant, complete) => (
    className={variant === 'left' ? styles.leftForm : styles.topForm}
    onSubscribe={complete}
    viewer={viewer}
    />
    )}

    View Slide

  123. function Card({ card }) {
    if (card.type === 'news') {
    return ;
    }
    if (card.type === 'post') {
    return ;
    }
    if (card.type === 'user') {
    return ;
    }
    return ;
    }

    View Slide

  124. const CARDS = {
    news: NewsCard,
    post: PostCard,
    user: UserCard,
    };
    function Card({ card }) {
    const Component = CARDS[card.type] || DefaultCard;
    return ;
    }

    View Slide

  125. function ShareButton({ sharable, medium }) {
    const icon = medium === 'twitter' ? : ;
    const onClick = () => {
    if (medium === 'facebook') {
    shareOnFacebook(sharable);
    } else {
    shareOnTwitter(sharable);
    }
    };
    return (
    icon={medium.icon}
    title={`Share on ${capitalize(medium)}`}
    onClick={onClick}
    />
    );
    }

    View Slide

  126. function ShareButton({ sharable, medium }) {
    const icon = medium === 'twitter' ? : ;
    const onClick = () => {
    if (medium === 'facebook') {
    shareOnFacebook(sharable);
    } else {
    shareOnTwitter(sharable);
    }
    };
    return (
    icon={medium.icon}
    title={`Share on ${capitalize(medium)}`}
    onClick={onClick}
    />
    );
    }

    View Slide

  127. const MEDIUMS = {
    twitter: {
    icon: ,
    title: 'Share on Twitter',
    share: shareOnTwitter,
    },
    facebook: {
    icon: ,
    title: 'Share on Facebook',
    share: shareOnFacebook,
    },
    };
    function ShareButton({ sharable, medium }) {
    const medium = MEDIUMS[medium];
    return (
    icon={medium.icon}
    title={medium.title}
    onClick={() => medium.share(sharable)}
    />
    );
    }

    View Slide

  128. const MEDIUMS = {
    twitter: {
    icon: ,
    title: 'Share on Twitter',
    share: shareOnTwitter,
    },
    facebook: {
    icon: ,
    title: 'Share on Facebook',
    share: shareOnFacebook,
    },
    linkedin: {
    icon: ,
    title: 'Share on LinkedIn',
    share: shareOnLinkedIn,
    },
    };
    function ShareButton({ sharable, medium }) {
    const medium = MEDIUMS[medium];
    return (
    icon={medium.icon}
    title={medium.title}
    onClick={() => medium.share(sharable)}
    />

    View Slide

  129. interface IProps {
    sharable: ISharable;
    medium: keyof typeof MEDIUMS;
    }

    View Slide

  130. http://blog.rstankov.com/replace-conditional-with-map-refactoring/

    View Slide

  131. #3
    Too DRY code

    View Slide

  132. View Slide

  133. Good DRY

    View Slide

  134. The bad side of DRY

    View Slide

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

    View Slide

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

    View Slide

  137. function path(rest = '') {
    return `${BASE_PATH}${rest}`;
    }
    function token(string) {
    return `${SEPARATOR}${string}`;
    }
    const SEPARATOR = '/';
    const API = 'api';
    const SOURCE_TYPE = ':source_type';
    const SOURCE_ID = ':id';
    const YEAR = ':year';
    const MONTH = ':month';
    const DAY = ':day';
    const SUBTYPE = ':subtype';
    const SUBID = ':subtype_id';
    const DETAILS = 'details';
    const ON = 'on';
    const SUB = 'sub';
    const BASE_PATH = token(API) + token(SOURCE_TYPE) + token(SOURCE_ID);
    const DATE_PART = token(YEAR) + token(MONTH) + token(DAY);
    const SUB_PART = token(SUBTYPE) + token(SUBID);
    const API_GET = path();
    const API_GET_DETAILS = path(token(DETAILS));
    const API_GET_VERSION = path(token(ON) + token(DATE_PART));
    const API_GET_SUBTYPE = path(token(SUB) + token(SUB_PART));

    View Slide

  138. View Slide

  139. Don't repeat yourself (DRY) is
    a principle of software development aimed at
    reducing repetition of software patterns, replacing
    it with abstractions or using data normalization to
    avoid redundancy.
    Don't repeat yourself

    View Slide

  140. The DRY principle is stated as "Every piece of
    knowledge must have a single,
    unambiguous, authoritative
    representation within a system"
    Don't repeat yourself

    View Slide

  141. #4
    Single Level of Abstraction

    View Slide

  142. SLAP
    Single Level of Abstraction Principle
    SLAP

    View Slide


  143. View Slide



  144. View Slide

  145. function Cart() {
    const [cart, setData] = useState(selectData(DataSource));
    const callback = useCallback(selectData, []);
    useEffect(() => {
    const removeChangeListener = DataSource.addChangeListener(() =>
    setData(callback(DataSource)),
    );
    return removeChangeListener;
    }, [callback]);
    return (


    Cart ({cart.length})


    {cart.map(item => (



    ))}


    );
    }

    View Slide

  146. function Cart() {
    const [cart, setData] = useState(selectData(DataSource));
    const callback = useCallback(selectData, []);
    useEffect(() => {
    const removeChangeListener = DataSource.addChangeListener(() =>
    setData(callback(DataSource)),
    );
    return removeChangeListener;
    }, [callback]);
    return (


    Cart ({cart.length})


    {cart.map(item => (



    ))}


    );
    }

    View Slide

  147. function Cart() {
    const [cart, setData] = useState(selectData(DataSource));
    const callback = useCallback(selectData, []);
    useEffect(() => {
    const removeChangeListener = DataSource.addChangeListener(() =>
    setData(callback(DataSource)),
    );
    return removeChangeListener;
    }, [callback]);
    return (


    Cart ({cart.length})


    {cart.map(item => (



    ))}


    );
    }

    View Slide

  148. function Cart() {
    const cart = useData(getCartData);
    return (


    Cart ({cart.length})


    {cart.map(item => (



    ))}


    );
    }

    View Slide

  149. function useData(selectData: (data: DataSourceClass) => T): T {
    const [data, setData] = useState(selectData(DataSource));
    const callback = useCallback(selectData, []);
    useEffect(() => {
    const removeChangeListener = DataSource.addChangeListener(() =>
    setData(callback(DataSource)),
    );
    return removeChangeListener;
    }, [callback]);
    return data;
    }

    View Slide

  150. View Slide

  151. ( Duplicated Code
    ) Long Method
    * Large Class
    + Long Parameter List
    , Shotgun Surgery
    - Feature Envy
    . Data Clumps
    / Case Statements
    0 Parallel Inheritance Hierarchies
    1 Speculative Generality
    2 Temporary Field
    3 Message Chains
    4 Middle Man
    5 Alternative Classes with Different Interfaces
    6 Refused Bequest
    7 Comments
    8 Repetitive Boilerplate
    9 God object '
    : and more ...

    View Slide

  152. View Slide

  153. View Slide

  154. View Slide

  155. View Slide

  156. Thanks ;

    View Slide

  157. https://speakerdeck.com/rstankov

    View Slide

  158. View Slide