+ All Categories
Home > Internet > Quality code by design

Quality code by design

Date post: 15-Aug-2015
Category:
Upload: wp-developers-club
View: 46 times
Download: 0 times
Share this document with a friend
Popular Tags:
52
Quality Code by Design by Tonya @hellofromTonya
Transcript

Quality Code by Designby Tonya

@hellofromTonya

@hellofromTonyaQuality Code by Design

Hello, I’m Tonya

Happy go-lucky Software & Electrical Engineer who finds coding, helping people, & solving problems fun.

Where can you find me?

@WP_Devs_Club

https://wpdevelopersclub.com

3 decades of professional experience

Spent 20+ years build & consulting on automated manufacturing systems

Then I found WordPress & Genesis

…and now I teach.

Know the Code Show(on Wednesdays)

Code is Our Craft

We are Software Developers

…Our Art

@hellofromTonyaQuality Code by Design

We should care about the Quality of our code

Let’s discover the Why, How, and When.

@hellofromTonyaQuality Code by Design

“There is a big difference in writing code that works

vs.crafting quality code that

works.”

@hellofromTonyaQuality Code by Design

It works, but…

do you want to maintain it?

@hellofromTonyaQuality Code by Design

Well crafted.

@hellofromTonyaQuality Code by Design

The Why

@hellofromTonyaQuality Code by Design

More predictableresults & behaviors

Easier to maintain

Easier to edit & extend

The Why

Easier to test

Elevates your craftMaximizes your fun

factor!

RespectRecognitio

n

@hellofromTonyaQuality Code by Design

The How

@hellofromTonyaQuality Code by Design

Code SmellsIf you’re code

has any of these,

you might be

smelly.

@hellofromTonyaQuality Code by Design

Project Map, Spec, PlanJust start writing code without a written

project plan.

NEVER..ever…ever…

write a single line of code without a

written spec, map, or plan.

@hellofromTonyaQuality Code by Design

Why?

@hellofromTonyaQuality Code by Design

vs.

@hellofromTonyaQuality Code by Design

the Pledge

I ____________ do pledge to NEVER EVER write a single

line of code until I have a plan.

@hellofromTonyaQuality Code by Design

Meet the All-in-One Child Theme

@hellofromTonyaQuality Code by Design

Common Project Spec

Child Theme

Child themeTheme code

Widgets

Custom Taxonomy

Custom Fields & Metaboxes

Portfolio

FAQ

Admin Settings Pages

Shortcodes

@hellofromTonyaQuality Code by Design

This just in…the project is smelly…

@hellofromTonyaQuality Code by Design

• Change the theme - functionality is gone.

• Repeating code…over & over & over

• Code is not reusable without edits

• Hard to maintain

• Hard to modify & extend

Problems with the all-in-one theme

@hellofromTonyaQuality Code by Design

QualityProjectStarting Line-Up

@hellofromTonyaQuality Code by Design

• Themes are for presentation

• Plugins are for functionality

• Don’t intermingle

• Never ever repeat

• Organize by purpose

• Function - single tasking (does ONE thing only)

Rules of Thumb

• DRY

• Separation of Concerns

• Single Responsibility

• etc.

@hellofromTonyaQuality Code by Design

Say Hello to the Theme Core Plugin

CorePlugin

WidgetsCore functionality

Base ClassesAdmin Settings

Shortcodes

The companion in every project.

Example available on GitHub:https://github.com/wpdevelopersclub/WPDC_Core

@hellofromTonyaQuality Code by Design

Hello Config File

A configuration file set the starting

point before the work begins.

It gives a module and its

submodules what they need to

start their work.

@hellofromTonyaQuality Code by Design

Huh? Why load a config file?

@hellofromTonyaQuality Code by Design

“Abstracting fluid config & setup parameters

allows your functional code to be … reusable.”

Think ahead. Think modular.

@hellofromTonyaQuality Code by Design

What goes into a Config file?

Config

Everything that “configures”, sets a “default” state, and/or sets a starting point.

Sidebar configShortcodes$defaults

Widgets$defaults, $widget_ops, $control_ops, $control

Image sizes add_image_size()

Theme support add_theme_support()()

Custom Post Typesregister_post_type()

@hellofromTonyaQuality Code by Design

Refactored Project Scope

Portfolio Plugin

FAQ Plugin

Child Theme’sPresentational Code

Child theme

Core Plugin

These files feed their respective

code

@hellofromTonyaQuality Code by Design

WeEnjoyTyping

meet the repeatie developer

@hellofromTonyaQuality Code by Design

Repeating patterns// Register widget areasgenesis_register_sidebar( array(

'id' => 'home-top','name' => __( 'Home - Top', 'magazine' ),'description' => __( 'This is the top section of the homepage.', ‘my-theme' ),

) );genesis_register_sidebar( array(

'id' => 'home-middle','name' => __( 'Home - Middle', 'magazine' ),'description' => __( 'This is the middle section of the homepage.', 'my-theme' ),

) );genesis_register_sidebar( array(

'id' => 'home-bottom','name' => __( 'Home - Bottom', 'magazine' ),'description' => __( 'This is the bottom section of the homepage.', 'my-theme' ),

) );genesis_register_sidebar( array(

'id' => 'after-entry','name' => __( 'After Entry', 'magazine' ),'description' => __( 'This is the after entry section.', 'my-theme' ),

) );

1

2

3

4

@hellofromTonyaQuality Code by Design

DRY Version

function register_sidebar( array $sidebars_config ) {

foreach ( $sidebars_config as $sidebar_config ) {genesis_register_sidebar( $sidebar_config );

}}

lib/support/theme-setup.php

@hellofromTonyaQuality Code by Design

Repeating patterns 2register_post_type( 'portfolio',

array('labels' => array(

'name' => __( 'Portfolio', 'my_theme' ),'singular_name' => __( 'Portfolio', 'my_theme' ),

),'exclude_from_search' => true,'has_archive' => true,'hierarchical' => true,'menu_icon' => 'dashicons-admin-page','public' => true,'rewrite' => array( 'slug' => 'portfolio', 'with_front' => false ),'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields', 'revisions', 'page-attributes', 'genesis-seo' ),

));

register_post_type('faq',array(

'labels' => array('name' => __( 'FAQ', 'my_theme' ),'singular_name' => __( 'FAQ', 'my_theme' ),

),'exclude_from_search' => true,'has_archive' => true,'hierarchical' => true,'menu_icon' => 'dashicons-admin-page','public' => true,'rewrite' => array( 'slug' => 'faq', 'with_front' => false ),'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields', 'revisions', 'page-attributes', 'genesis-seo' ),

));

1

2

@hellofromTonyaQuality Code by Design

DRY Version

function mycore_register_custom_post_types( array $cpts ) {foreach ( $cpts as $slug => $cpt_config ) {

register_post_type( $slug, $cpt_config );}

}

lib/custom/cpts.php

@hellofromTonyaQuality Code by Design

the DRY Principle

I will not repeat myself

I will not repeat myself

I will not

I will not repeat myselfI will not repeat myselfI will not repeat myself

I will not repeat myself

I will not repeat myself

I will not repeat myself

@hellofromTonyaQuality Code by Design

I LikeDoingToo Much

meet Mr. Multitasker

@hellofromTonyaQuality Code by Design

The Overachiever Patternfunction get_classes_for_grid_pattern( array $classes, $number_of_columns = 2 ) {

// If number of columns is less than 2, there's no reason to continue.// We are only allowing up to 6 columns; therefore, bail out if we// want more.if ( $number_of_columns < 2 || $number_of_columns > 6 ) {

return $classes;}

switch( $number_of_columns ) {case 6:

$classes[] = 'one-sixth';break;

case 5:$classes[] = 'one-fifth';break;

case 4:$classes[] = 'one-fourth';break;

case 3:$classes[] = 'one-third';break;

default:$classes[] = 'one-half';break;

}

global $wp_query;

if ( $wp_query->current_post % $number_of_columns == 0 ) {$classes[] = 'first';

}

return $classes;}

1

2

3

4

@hellofromTonyaQuality Code by Design

Abstract columns styling classes:

function get_column_class( $number_of_columns ) {$column_classes = array(

'', // index 0'', // index 1'one-half', // index 2 = represents 2 columns'one-third', // index 3'one-fourth', // index 4'one-fifth', // index 5'one-sixth', // index 6

);

return $number_of_columns <= 6? $column_classes[ $number_of_columns ]: '';

}

switch( $number_of_columns ) {case 6:

$classes[] = 'one-sixth';break;

case 5:$classes[] = 'one-fifth';break;

case 4:$classes[] = 'one-fourth';break;

case 3:$classes[] = 'one-third';break;

default:$classes[] = 'one-half';break;

}

function get_classes_for_grid_pattern( array $classes, $number_of_columns = 2 ) {$column_class = get_column_class( $number_of_columns );if ( ! $column_class ) {

return $classes;}$classes[] = $column_class;

1

2

@hellofromTonyaQuality Code by Design

Abstract out the 1st column code

function get_first_column_styling_class( $number_of_columns ) {global $wp_query;return $wp_query->current_post % $number_of_columns == 0 ? 'first' : '';

}

global $wp_query;if ( $wp_query->current_post % $number_of_columns == 0 ) {

$classes[] = 'first';}

function get_classes_for_grid_pattern( array $classes, $number_of_columns = 2 ) {$column_class = get_column_class( $number_of_columns );if ( ! $column_class ) {

return $classes;}$classes[] = $column_class;

$first = get_first_column_styling_class( $number_of_columns );if ( ! $first ) {

$classes[] = $first;}

return $classes;}

Do you see an opportunity to refactor more?

3

@hellofromTonyaQuality Code by Design

Getting it down to 1 thing:

function get_classes_for_grid_pattern( $number_of_columns = 2 ) {$column_class = get_column_class( $number_of_columns );if ( ! $column_class ) {

return false;}

$first = get_first_column_styling_class( $number_of_columns );

return $first ? array( $column_class, $first ) : array( $column_class );}

function get_classes_for_grid_pattern( array $classes, $number_of_columns = 2 ) {$column_class = get_column_class( $number_of_columns );if ( ! $column_class ) {

return $classes;}$classes[] = $column_class;

$first = get_first_column_styling_class( $number_of_columns );if ( ! $first ) {

$classes[] = $first;}

return $classes;}

Now what is the single responsibility of the function?

1

2

@hellofromTonyaQuality Code by Design

Complete Refactored Codeadd_filter( 'post_class', __NAMESPACE__ . '\\add_to_post_classes_for_grid_pattern' );function add_to_post_classes_for_grid_pattern( array $classes ) {

$column_classes = get_classes_for_grid_pattern( $classes, 2 );return empty( $column_classes ) ? $classes : array_merge( $classes, $column_classes );

}

function get_classes_for_grid_pattern( $number_of_columns = 2 ) {$column_class = get_column_class( $number_of_columns );if ( ! $column_class ) {

return false;}

$first = get_first_column_styling_class( $number_of_columns );

return $first ? array( $column_class, $first ) : array( $column_class );}

function get_first_column_styling_class( $number_of_columns ) {global $wp_query;return $wp_query->current_post % $number_of_columns == 0 ? 'first' : '';

}

function get_column_class( $number_of_columns ) {$column_classes = array(

'', // index 0'', // index 1'one-half', // index 2'one-third', // index 3'one-fourth', // index 4'one-fifth', // index 5'one-sixth', // index 6

);

return $number_of_columns <= 6? $column_classes[ $number_of_columns ]: '';

}

@hellofromTonyaQuality Code by Design

Other refactoring for decision trees

$processing_funcs = array('text' => __NAMESPACE__ . '\\process_text_field','number' => __NAMESPACE__ . '\\process_number_field','date' => __NAMESPACE__ . '\\process_date_field',

);

$func_name = $processing_funcs[ $field->type ];$func_name( $field );

Variable function

$processing_funcs = array('text' => __NAMESPACE__ . '\\process_text_field','number' => __NAMESPACE__ . '\\process_number_field','date' => __NAMESPACE__ . '\\process_date_field',

);

call_user_func( $processing_funcs[ $field->type ], $field );

call_user_func() or call_user_func_array()

@hellofromTonyaQuality Code by Design

Views are for HTMLclass My_Superduper_Widget extends WP_Widget {

function form( $instance ) {

//* Merge with defaults$instance = wp_parse_args( (array) $instance, $this->defaults );

?><p>

<label for="<?php echo $this->get_field_id( 'title' ); ?>”><?php _e( 'Title', 'genesis' ); ?>:

</label><input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>”

</p>

class My_Superduper_Widget extends WP_Widget {

protected $form_view = '/lib/views/my-superduper-widget.php';

function form( $instance ) {

//* Merge with defaults$instance = wp_parse_args( (array) $instance, $this->defaults );

include( CHILD_DIR . $this->form_view );

@hellofromTonyaQuality Code by Design

• Well organized

• Focused & purposeful

• Modular

• More maintainable

• Changes occur in one

spot

• Much easier to test

• Skinny

• More predictable

@hellofromTonyaQuality Code by Design

Guess WhatI Do

meet Mr. Guess

@hellofromTonyaQuality Code by Design

Purposeful naming

function do_classes( array $classes, $num = 2 ) {// Number the columns required is less than 2, then...if ( $num < 2 ) {}

}

function get_classes_for_grid_pattern( array $post_classes, $number_of_columns = 2 ) {// do some cool stuff....

}

What does do_classes() do? What does $num represent?

@hellofromTonyaQuality Code by Design

Purposeful Naming ConventionName functions, methods, and classes by what they

DO.Name variables by what they represent.

@hellofromTonyaQuality Code by Design

Let your code tell…• More readable code

• Self-documenting

• Skinny functions & methods

• Defines the purpose to ensure the code supports its

parent.

@hellofromTonyaQuality Code by Design

One more exercise in Refactoring

@hellofromTonyaQuality Code by Design

Additional Refactoringfunction my_cool_shortcode( $atts ) {

$defaults = array('after' => '','before' => '','format' => get_option( 'date_format' ),'label' => '',

);

$atts = shortcode_atts( $defaults, $atts );// now do the shortcode work

}

function my_other_cool_shortcode( $atts ) {

$defaults = array('after' => '','before' => '','format' => get_option( 'time_format' ),'label' => '',

);

$atts = shortcode_atts( $defaults, $atts );// now do the shortcode work

}

@hellofromTonyaQuality Code by Design

Refactored Functional Shortcodesfunction my_cool_shortcode( $atts ) {

mcp_get_shortcode_atts( 'my_cool_shortcode', $atts );// now do the shortcode work

}

function my_other_cool_shortcode( $atts ) {

mcp_get_shortcode_atts( 'my_other_cool_shortcode', $atts );// now do the shortcode work

}

function mcp_get_shortcode_config( $config_key ) {static $config = array();if ( empty( $config ) ) {

$config = require_once( MY_CORE_PLUGIN_DIR . ‘/config/shortcodes.php' );}

if ( array_key_exists( $config_key, $config ) ) {return $config[ $config_key ];

}

new InvalidArgumentException(__( 'Shortcode configuration key does not exist.', 'my_cool_plugin' )

);}

function mcp_get_shortcode_atts( $config_key, &$atts ) {

$defaults = wp_parse_args(mcp_get_shortcode_config( $config_key ),array(

'after' => '','before' => '',

));

$atts = shortcode_atts( $defaults, $atts );}

@hellofromTonyaQuality Code by Design

Refactored Shortcodes in OOP<?php namespace WPDevsClub_Core\Shortcodes;

abstract class Shortcode implements I_Shortcode {

protected $config = array();protected $defaults = array();protected $atts = array();

public function __config( array $config ) {$this->init_config( $config );$this->init_hooks();

}

protected function init_hooks() {add_shortcode(

$this->config['shortcode_key'],array( $this, 'do_shortcode' )

);}

public function do_shortcode( $atts ) {$this->merge_atts_with_defaults( $atts );$this->do_functional_work();return $this->render();

}

protected function render() {do_start();include( $this->config['view_file'] );return ob_get_clean();

}

protected function init_config( $config ) {$this->config = $config;$this->defaults = wp_parse_args(

$this->config['defaults'],array(

'after' => '','before' => '',

));

}

abstract function do_functional_work();

protected function merge_atts_with_defaults( $atts ) {$this->atts = shortcode_atts( $this->defaults, $atts );

}}

@hellofromTonyaQuality Code by Design

Super Sniffer Clues

1.Long functions, classes, or methods

2.Vague naming

3.Multi-leveled conditional trees (selects & ifs)

4.Asking first. (not being ready to work at the

start)

@hellofromTonyaQuality Code by Design

More infoKeys to Writing Quality Code

https://wpdevelopersclub.com/keys-to-writing-quality-code/

Software Development Core Principles

https://wpdevelopersclub.com/software-development-core-principles/

Come join me each Wednesday onKnow the Code Show

https://hub.wpdevelopersclub.com/know-the-code-show-podcast-tutorials/


Recommended