SlideShare uma empresa Scribd logo
1 de 57
Baixar para ler offline
Pague o aluguel
Trabalhando efetivamente com código em débito
Eu sou…
• Desenvolvedor;
• PHP, Ruby, Python e JavaScript. Um pouco de Java e C# (Xamarin);
• Trabalho na BriteCore;
• Trabalho remotamente desde 2016;
• @nelson_senna
Dívida
“…fazendo as
coisas de
maneira rápida e
suja cria-se um
débito técnico…”
–Martin Fowler
Débito técnico é…
Código usado para protótipos, provas de
conceito ou até uma pequena correção.
Classificação de débito técnico
Imprudente Prudente
Deliberado
Negligente
“Não temos tempo!” “Precisamos entregar,
depois vemos isso.”
“O que é OOD? OOP? Design?”
“Agora sabemos que
devíamos ter feito isso.”
Débito técnico é…
Código que deveríamos jogar fora…
–Martin Fowler
“Como uma dívida
financeira, o débito
técnico incorre em
pagamentos de juros,
que vêm na forma de
esforço extra que
temos que fazer no
futuro...”
Efeitos da dívida
“…esse código muitas
vezes ganha vida
própria… Funciona,
então por que
consertar?”
–Brian Foote
E algum tempo e “ifs”
depois…
“Um Big Ball of Mud
tem estrutura
desordenada,
espalhada, desleixada,
remendada e, código
espaguete”
–Brian Foote
Big Ball of Mud
• Os nomes de variáveis e funções pouco informativos ou enganosos
• Uso extensivo de variáveis globais
• Métodos com longas listas de parâmetros mal definidos
• Métodos longos e complicados e, executam várias tarefas não relacionadas
• Código duplicado
• O fluxo de controle é difícil de entender e difícil de seguir
• A intenção do programador é quase impossível de discernir
• O código é simplesmente ilegível e espalhado sem modularização clara
• O código exibe os sinais inconfundíveis de patch após patch nas mãos de vários
mantenedores, cada um dos quais mal entendeu as conseqüências do que estava
fazendo
• Sem documentação
Big Ball of Mud
A estrutura rígida que faz com que o
código fique difícil de entender, caro e
suscetível a erros.
“Da sinonímia dos termos organização e
conhecimento, retira-se que a síntese mais
produtiva, ou mais instigadora, para a
construção de uma idéia acerca da
organização do conhecimento na sociedade é
aquela que abstrai de organização, pelo verbo
organizar, os sentidos de ORGANIZAR, que
são os seguintes: estabelecer as bases de;
arrumar de determinado modo; colocar em
certa ordem.”
–Renato Rocha Souza
Entender é…
Organizar ideias e conceitos, atribuindo
uma ordem, classificando os mesmos.
Então…
if (organizacao) {
entendimento++;
bigBallOfMud--;
}
Pagando a dívida
Entender é…
Organizar ideias e conceitos, atribuindo
uma ordem, classificando os mesmos.
Nome é…
Palavra ou locução com que se designa
uma classe de coisas, pessoas, animais,
um lugar, um acidente geográfico, um
astro etc.
“Existem duas coisas
difíceis em computação:
invalidação de cache e
nomear coisas.”
–Phil Karlton
Nomes são…
DESCOBERTOS!
Nomes são descobertos!
Sem nome
Sem
sentido
Honesto
Honesto e
Completo
Faz o que o
nome diz
Intenção
↪ ↪ ↪ ↪ ↪ ↪
Abstração de
domínio
Nomes são descobertos!
Sem nome
Sem
sentido
Honesto
Honesto e
Completo
Faz o que o
nome diz
Intenção
↪ ↪ ↪ ↪ ↪ ↪
Abstração de
domínio
@arlobelshee
var rootJquery,
// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
// Shortcut simple #id case for speed
rquickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]+))$/,
init = jQuery.fn.init = function( selector, context, root ) {
var match, elem;
// HANDLE: $(""), $(null), $(undefined), $(false)
if (!selector) {
return this;
}
// Method init() accepts an alternate rootjQuery
// so migrate can support jQuery.sub (gh-2101)
root = root || rootjQuery;
// Handle HTML strings
if (typeof selector === "string") {
if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [null, selector, null];
} else {
match = rquickExpr.exec( selector );
}
…
// HANDLE: $(expr, $(...))
} else if (!context || context.jquery) {
return (context || root).find(selector);
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor(context).find(selector);
}
// HANDLE: $(DOMElement)
} else if (selector.nodeType) {
this[0] = selector;
this.length = 1;
return this;
// HANDLE: $(function)
// Shortcut for document ready
} else if (isFunction(selector)) {
return root.ready !== undefined ? root.ready(selector) :
// Execute immediately if ready is not present
selector(jQuery);
}
return jQuery.makeArray(selector, this);
};
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
context = context instanceof jQuery ? context[0] : context;
// Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge(this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
));
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
for (match in context) {
// Properties of context are called as methods if possible
if (isFunction(this[match])) {
this[match](context[match]);
// ...and otherwise set as attributes
} else {
this.attr(match, context[match]);
}
}
}
return this;
// HANDLE: $(#id)
} else {
elem = document.getElementById(match[2]);
if (elem) {
// Inject the element directly into the jQuery object
this[0] = elem;
this.length = 1;
}
return this;
}
var rootJquery,
// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
// Shortcut simple #id case for speed
rquickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]+))$/,
init = jQuery.fn.init = function( selector, context, root ) {
var match, elem;
// HANDLE: $(""), $(null), $(undefined), $(false)
if (!selector) {
return this;
}
// Method init() accepts an alternate rootjQuery
// so migrate can support jQuery.sub (gh-2101)
root = root || rootjQuery;
// Handle HTML strings
if (typeof selector === "string") {
if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [null, selector, null];
} else {
match = rquickExpr.exec( selector );
}
…
// HANDLE: $(expr, $(...))
} else if (!context || context.jquery) {
return (context || root).find(selector);
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor(context).find(selector);
}
// HANDLE: $(DOMElement)
} else if (selector.nodeType) {
this[0] = selector;
this.length = 1;
return this;
// HANDLE: $(function)
// Shortcut for document ready
} else if (isFunction(selector)) {
return root.ready !== undefined ? root.ready(selector) :
// Execute immediately if ready is not present
selector(jQuery);
}
return jQuery.makeArray(selector, this);
};
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
context = context instanceof jQuery ? context[0] : context;
// Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge(this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
));
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
for (match in context) {
// Properties of context are called as methods if possible
if (isFunction(this[match])) {
this[match](context[match]);
// ...and otherwise set as attributes
} else {
this.attr(match, context[match]);
}
}
}
return this;
// HANDLE: $(#id)
} else {
elem = document.getElementById(match[2]);
if (elem) {
// Inject the element directly into the jQuery object
this[0] = elem;
this.length = 1;
}
return this;
}
jQuery( selector [, context ] )
jQuery( element )
jQuery( elementArray )
jQuery( object )
jQuery( selection )
jQuery()
jQuery( html [, ownerDocument ] )
jQuery( html, attributes )
jQuery( callback )
var rootJquery,
// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
// Shortcut simple #id case for speed
rquickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]+))$/,
init = jQuery.fn.init = function( selector, context, root ) {
var match, elem;
// HANDLE: $(""), $(null), $(undefined), $(false)
if (!selector) {
return this;
}
// Method init() accepts an alternate rootjQuery
// so migrate can support jQuery.sub (gh-2101)
root = root || rootjQuery;
// Handle HTML strings
if (typeof selector === "string") {
if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [null, selector, null];
} else {
match = rquickExpr.exec( selector );
}
…
// HANDLE: $(expr, $(...))
} else if (!context || context.jquery) {
return (context || root).find(selector);
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor(context).find(selector);
}
// HANDLE: $(DOMElement)
} else if (selector.nodeType) {
this[0] = selector;
this.length = 1;
return this;
// HANDLE: $(function)
// Shortcut for document ready
} else if (isFunction(selector)) {
return root.ready !== undefined ? root.ready(selector) :
// Execute immediately if ready is not present
selector(jQuery);
}
return jQuery.makeArray(selector, this);
};
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
context = context instanceof jQuery ? context[0] : context;
// Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge(this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
));
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
for (match in context) {
// Properties of context are called as methods if possible
if (isFunction(this[match])) {
this[match](context[match]);
// ...and otherwise set as attributes
} else {
this.attr(match, context[match]);
}
}
}
return this;
// HANDLE: $(#id)
} else {
elem = document.getElementById(match[2]);
if (elem) {
// Inject the element directly into the jQuery object
this[0] = elem;
this.length = 1;
}
return this;
}
Sem nome!
var handleHTMLStrings = function (selector, context, root) {
if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [null, selector, null];
} else {
match = rquickExpr.exec( selector );
}
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
// ...
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
// ...
}
return this;
// HANDLE: $(#id)
} else {
// ...
}
// HANDLE: $(expr, $(...))
} else if (!context || context.jquery) {
// ...
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
// ...
}
}
Sem sentido!
var handleHTMLStrings = function (selector, context, root) {
if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [null, selector, null];
} else {
match = rquickExpr.exec( selector );
}
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
// ...
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
// ...
}
return this;
// HANDLE: $(#id)
} else {
// ...
}
// HANDLE: $(expr, $(...))
} else if (!context || context.jquery) {
// ...
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
// ...
}
}
var handleHTMLStringsAndElementIds = function (selector, context, root) {
if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [null, selector, null];
} else {
match = rquickExpr.exec( selector );
}
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
// ...
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
// ...
}
return this;
// HANDLE: $(#id)
} else {
// ...
}
// HANDLE: $(expr, $(...))
} else if (!context || context.jquery) {
// ...
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
// ...
}
}
Honesto!
var handleHTMLStringsAndElementIds = function (selector, context, root) {
if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [null, selector, null];
} else {
match = rquickExpr.exec( selector );
}
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
// ...
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
// ...
}
return this;
// HANDLE: $(#id)
} else {
// ...
}
// HANDLE: $(expr, $(...))
} else if (!context || context.jquery) {
// ...
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
// ...
}
}
var handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root) {
if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [null, selector, null];
} else {
match = rquickExpr.exec( selector );
}
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
// ...
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
// ...
}
return this;
// HANDLE: $(#id)
} else {
// ...
}
// HANDLE: $(expr, $(...))
} else if (!context || context.jquery) {
// ...
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
// ...
}
}
Honesto e
completo!
handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root)
handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root)
handleHTMLStrings = function (selector, context, root)
handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root)
handleHTMLStrings = function (selector, context, root)
handleElementIds = function (selector, context, root)
handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root)
handleHTMLStrings = function (selector, context, root)
handleElementIds = function (selector, context, root)
handleCSSSelectors = function (selector, context, root)
handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root)
handleHTMLStrings = function (selector, context, root)
handleElementIds = function (selector, context, root)
handleCSSSelectors = function (selector, context, root)
var handleHTMLStrings = function (match, context, root) {
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
context = context instanceof jQuery ? context[0] : context;
// Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge(this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
));
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
for (match in context) {
// Properties of context are called as methods if possible
if (isFunction(this[match])) {
this[match](context[match]);
// ...and otherwise set as attributes
} else {
this.attr(match, context[match]);
}
}
}
return this;
}
}
}
Sem sentido?
Características de bons nomes de métodos
• Use verbos*;
• Sem abreviações;
• Conciso (mas, não muito!);
• Use perguntas quando o método retornar um boolean (isEmpty(), canDo());
• Não use “And” e “Or” nos seus nomes;
• Não deixe o nome redundante com o argumento

($list->addItem($item));
• Não deixe o nome redundante com quem chama

($list->addToList($item));
var buildFromHTMLString = function (match, context, root) {
// Match html or make sure no context is specified for #id
if (match && (match[1] || !context)) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
context = context instanceof jQuery ? context[0] : context;
// Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge(this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
));
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
for (match in context) {
// Properties of context are called as methods if possible
if (isFunction(this[match])) {
this[match](context[match]);
// ...and otherwise set as attributes
} else {
this.attr(match, context[match]);
}
}
}
return this;
}
}
}
Temos um bom nome?
• Use verbos* √
• Sem abreviações √
• Conciso (mas, não muito!) √
• Use perguntas quando o método retornar um boolean (isEmpty(), canDo()) √
• Não use “And” e “Or” nos seus nomes √
• Não deixe o nome redundante com o argumento √
• Não deixe o nome redundante com quem chama √
var fromHTMLString = function (match, context) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
context = context instanceof jQuery ? context[0] : context;
// Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge(this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
));
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
for (match in context) {
// Properties of context are called as methods if possible
if (isFunction(this[match])) {
this[match](context[match]);
// ...and otherwise set as attributes
} else {
this.attr(match, context[match]);
}
}
}
return this;
}
}
var fromHTMLString = function (match, context) {
// HANDLE: $(html) -> $(array)
if (match[1]) {
context = context instanceof jQuery ? context[0] : context;
// Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge(this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
));
// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
for (match in context) {
// Properties of context are called as methods if possible
if (isFunction(this[match])) {
this[match](context[match]);
// ...and otherwise set as attributes
} else {
this.attr(match, context[match]);
}
}
}
return this;
}
}
Características de bons nomes de variáveis
• Sem abreviações;
• Conciso (mas, não muito!);
• Use perguntas quando o método retornar um boolean (isEmpty, canDo);
• Não use “And” e “Or” nos seus nomes;
var fromHTMLString = function (source, context) {
if (source) {
context = context instanceof jQuery ? context[0] : context;
var runScriptsForBackCompat = true
var isNode = context && context.nodeType;
var contextDocument = isNode ? context.ownerDocument || context : document;
jQuery.merge(this, jQuery.parseHTML(source, contextDocument, runScriptsForBackCompat));
var isSingleTagWithoutAttributes = rsingleTag.test(source)
var isAttributesSuperSet = jQuery.isPlainObject(context);
if (isSingleTagWithoutAttributes && isAttributesSuperSet) {
for (attributeName in context) {
// Properties of context are called as methods if possible
if (isFunction(this[attributeName])) {
this[attributeName](context[attributeName]);
// ...and otherwise set as attributes
} else {
this.attr(attributeName, context[attributeName]);
}
}
}
return this;
}
}
var fromHTMLString = function (source, context) {
if (source) {
context = context instanceof jQuery ? context[0] : context;
var runScriptsForBackCompat = true
var isNode = context && context.nodeType;
var contextDocument = isNode ? context.ownerDocument || context : document;
jQuery.merge(this, jQuery.parseHTML(source, contextDocument, runScriptsForBackCompat));
var isSingleTagWithoutAttributes = rsingleTag.test(source)
var isAttributesSuperSet = jQuery.isPlainObject(context);
if (isSingleTagWithoutAttributes && isAttributesSuperSet) {
for (attributeName in context) {
// Properties of context are called as methods if possible
if (isFunction(this[attributeName])) {
this[attributeName](context[attributeName]);
// ...and otherwise set as attributes
} else {
this.attr(attributeName, context[attributeName]);
}
}
}
return this;
}
}
Características de bons nomes de classes
• Use substantivos e adjetivos*;
• Não use muitos adjetivos (AbstractFactoryPatternBase);
• Não use “Manager”, “Helper” e “Data” nos seus nomes;
• Não use Sufixos do seu namespace (Service, Factory, Iterator)
• Evite usar “er”, “or”, “tion”, “sion” (ObjectFinder, DataProcessor, Conversion,
DataManipulation)
–Chris Oldwood
“So, a "DateTimeProvider", that's
basically just a clock, right?”
Características de bons nomes de variáveis
Service is the new Enzo
var HTMLCreationContext = function (elementOrAttributes) {
this.elementOrAttributes = elementOrAttributes;
}
HTMLCreationContext.prototype = {
isNode: function () {
return (this.elementOrAttributes && this.elementOrAttributes.nodeType);
},
getOwnerDocument: function () {
if (this.isNode) {
return this.elementOrAttributes.ownerDocument || this.elementOrAttributes;
}
return document;
},
getAttributesSuperSet: function () {
if (jQuery.isPlainObject(this.elementOrAttributes)) {
return this.elementOrAttributes;
}
return {};
},
getMergeContext: function () {
if (this.elementOrAttributes instanceof jQuery) {
return this.elementOrAttributes[0];
}
return this.elementOrAttributes;
}
}
var HTMLCreationContext = function (elementOrAttributes) {
this.elementOrAttributes = elementOrAttributes;
}
HTMLCreationContext.prototype = {
isNode: function () {
return (this.elementOrAttributes && this.elementOrAttributes.nodeType);
},
getOwnerDocument: function () {
if (this.isNode) {
return this.elementOrAttributes.ownerDocument || this.elementOrAttributes;
}
return document;
},
getAttributesSuperSet: function () {
if (jQuery.isPlainObject(this.elementOrAttributes)) {
return this.elementOrAttributes;
}
return {};
},
getMergeContext: function () {
if (this.elementOrAttributes instanceof jQuery) {
return this.elementOrAttributes[0];
}
return this.elementOrAttributes;
}
}
var fromHTMLString = function (source, context) {
if (source) {
var creationContext = new HTMLCreationContext(context);
var runScriptsForBackCompat = true
jQuery.merge(this, jQuery.parseHTML(
source,
creationContext.getOwnerDocument(),
runScriptsForBackCompat
));
var isSingleTagWithoutAttributes = rsingleTag.test(source)
if (isSingleTagWithoutAttributes) {
var attributes = creationContext.getAttributesSuperSet();
for (attributeName in attributes) {
// Properties of context are called as methods if possible
if (isFunction(this[attributeName])) {
this[attributeName](context[attributeName]);
// ...and otherwise set as attributes
} else {
this.attr(attributeName, context[attributeName]);
}
}
}
return this;
}
}
Concluindo…
1. Procure por lugares com mais de um nível de identação
2. Extraia e dê nome para o que fizer sentido
3. Descreva o que o método realmente faz, sem vergonha, seja honesto!
4. Vá diminuindo o nome do método extraindo suas responsabilidades
5. Excesso de métodos privados para um dado contexto: Uma nova classe!
6. Procure na documentação ou fale com um amiguinho para descrever

o problema de domínio resolvido
7. Seja feliz!
OBRIGADO!
Referências
•Foto dívida: https://flic.kr/p/oiBTYX
•https://martinfowler.com/bliki/TechnicalDebt.html
•https://martinfowler.com/bliki/
TechnicalDebtQuadrant.html
•http://www.laputan.org/mud/
mud.html#ThrowAwayCode
•http://www.laputan.org/mud/
•http://revista.ibict.br/ciinf/article/view/1058/1141

Mais conteúdo relacionado

Mais procurados

Documentacion edderson callpa_ortiz
Documentacion edderson callpa_ortizDocumentacion edderson callpa_ortiz
Documentacion edderson callpa_ortiz
Edderson J. Ortiz
 
Crud secara simultan ala php myadmin
Crud secara simultan ala php myadminCrud secara simultan ala php myadmin
Crud secara simultan ala php myadmin
Rizal Di Caprio
 
Php codigos interfaces fredy guzman cusihunca
Php codigos interfaces   fredy guzman cusihuncaPhp codigos interfaces   fredy guzman cusihunca
Php codigos interfaces fredy guzman cusihunca
Tigger_Fred
 
Twig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadasTwig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadas
Javier Eguiluz
 
Handbook - From jQuery to YUI 3
Handbook - From jQuery to YUI 3Handbook - From jQuery to YUI 3
Handbook - From jQuery to YUI 3
Ying-Hsiang Liao
 
Simular un next del recordset en php de forma rudimentaria
Simular un next del recordset en php de forma rudimentariaSimular un next del recordset en php de forma rudimentaria
Simular un next del recordset en php de forma rudimentaria
jbersosa
 

Mais procurados (20)

Iteratory
IteratoryIteratory
Iteratory
 
Analizador sintáctico de Pascal escrito en Bison
Analizador sintáctico de Pascal escrito en BisonAnalizador sintáctico de Pascal escrito en Bison
Analizador sintáctico de Pascal escrito en Bison
 
Practical JavaScript Programming - Session 2/8
Practical JavaScript Programming - Session 2/8Practical JavaScript Programming - Session 2/8
Practical JavaScript Programming - Session 2/8
 
jQuery PLUGIN
jQuery PLUGINjQuery PLUGIN
jQuery PLUGIN
 
Programming Java - Lection 03 - Classes - Lavrentyev Fedor
Programming Java - Lection 03 - Classes - Lavrentyev FedorProgramming Java - Lection 03 - Classes - Lavrentyev Fedor
Programming Java - Lection 03 - Classes - Lavrentyev Fedor
 
Documentacion edderson callpa_ortiz
Documentacion edderson callpa_ortizDocumentacion edderson callpa_ortiz
Documentacion edderson callpa_ortiz
 
Sis quiz
Sis quizSis quiz
Sis quiz
 
Jquery Introduction Hebrew
Jquery Introduction HebrewJquery Introduction Hebrew
Jquery Introduction Hebrew
 
Crud secara simultan ala php myadmin
Crud secara simultan ala php myadminCrud secara simultan ala php myadmin
Crud secara simultan ala php myadmin
 
Php codigos interfaces fredy guzman cusihunca
Php codigos interfaces   fredy guzman cusihuncaPhp codigos interfaces   fredy guzman cusihunca
Php codigos interfaces fredy guzman cusihunca
 
Testování prakticky
Testování praktickyTestování prakticky
Testování prakticky
 
1- Sourcecode Array
1- Sourcecode Array1- Sourcecode Array
1- Sourcecode Array
 
Twig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadasTwig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadas
 
jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginners
 
Index1
Index1Index1
Index1
 
Handbook - From jQuery to YUI 3
Handbook - From jQuery to YUI 3Handbook - From jQuery to YUI 3
Handbook - From jQuery to YUI 3
 
Wek14 mysql 2
Wek14 mysql 2Wek14 mysql 2
Wek14 mysql 2
 
Practical JavaScript Programming - Session 3/8
Practical JavaScript Programming - Session 3/8Practical JavaScript Programming - Session 3/8
Practical JavaScript Programming - Session 3/8
 
Jquery Framework
Jquery FrameworkJquery Framework
Jquery Framework
 
Simular un next del recordset en php de forma rudimentaria
Simular un next del recordset en php de forma rudimentariaSimular un next del recordset en php de forma rudimentaria
Simular un next del recordset en php de forma rudimentaria
 

Mais de Nelson Senna do Amaral

Mais de Nelson Senna do Amaral (10)

Veni vedi vici.
Veni vedi vici.Veni vedi vici.
Veni vedi vici.
 
Dando nome aos códigos
Dando nome aos códigosDando nome aos códigos
Dando nome aos códigos
 
Melhorando seu código com Law of Demeter e Tell don't ask
Melhorando seu código com Law of Demeter e Tell don't askMelhorando seu código com Law of Demeter e Tell don't ask
Melhorando seu código com Law of Demeter e Tell don't ask
 
OOP: Princípios e Padroes
OOP: Princípios e PadroesOOP: Princípios e Padroes
OOP: Princípios e Padroes
 
Ruby Gotchas
Ruby GotchasRuby Gotchas
Ruby Gotchas
 
Domínio: Dividir e conquistar
Domínio: Dividir e conquistarDomínio: Dividir e conquistar
Domínio: Dividir e conquistar
 
Interfaces - Como os objetos deveriam se comportar
Interfaces - Como os objetos deveriam se comportarInterfaces - Como os objetos deveriam se comportar
Interfaces - Como os objetos deveriam se comportar
 
Nossa experiência com TDD
Nossa experiência com TDDNossa experiência com TDD
Nossa experiência com TDD
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Tirando o coelho da cartola: integrando sistemas com RabbitMQ
Tirando o coelho da cartola: integrando sistemas com RabbitMQTirando o coelho da cartola: integrando sistemas com RabbitMQ
Tirando o coelho da cartola: integrando sistemas com RabbitMQ
 

Pague o aluguel

  • 1. Pague o aluguel Trabalhando efetivamente com código em débito
  • 2. Eu sou… • Desenvolvedor; • PHP, Ruby, Python e JavaScript. Um pouco de Java e C# (Xamarin); • Trabalho na BriteCore; • Trabalho remotamente desde 2016; • @nelson_senna
  • 4. “…fazendo as coisas de maneira rápida e suja cria-se um débito técnico…” –Martin Fowler
  • 5. Débito técnico é… Código usado para protótipos, provas de conceito ou até uma pequena correção.
  • 6. Classificação de débito técnico Imprudente Prudente Deliberado Negligente “Não temos tempo!” “Precisamos entregar, depois vemos isso.” “O que é OOD? OOP? Design?” “Agora sabemos que devíamos ter feito isso.”
  • 7. Débito técnico é… Código que deveríamos jogar fora…
  • 8. –Martin Fowler “Como uma dívida financeira, o débito técnico incorre em pagamentos de juros, que vêm na forma de esforço extra que temos que fazer no futuro...”
  • 10. “…esse código muitas vezes ganha vida própria… Funciona, então por que consertar?” –Brian Foote
  • 11. E algum tempo e “ifs” depois…
  • 12. “Um Big Ball of Mud tem estrutura desordenada, espalhada, desleixada, remendada e, código espaguete” –Brian Foote
  • 13. Big Ball of Mud • Os nomes de variáveis e funções pouco informativos ou enganosos • Uso extensivo de variáveis globais • Métodos com longas listas de parâmetros mal definidos • Métodos longos e complicados e, executam várias tarefas não relacionadas • Código duplicado • O fluxo de controle é difícil de entender e difícil de seguir • A intenção do programador é quase impossível de discernir • O código é simplesmente ilegível e espalhado sem modularização clara • O código exibe os sinais inconfundíveis de patch após patch nas mãos de vários mantenedores, cada um dos quais mal entendeu as conseqüências do que estava fazendo • Sem documentação
  • 14. Big Ball of Mud A estrutura rígida que faz com que o código fique difícil de entender, caro e suscetível a erros.
  • 15. “Da sinonímia dos termos organização e conhecimento, retira-se que a síntese mais produtiva, ou mais instigadora, para a construção de uma idéia acerca da organização do conhecimento na sociedade é aquela que abstrai de organização, pelo verbo organizar, os sentidos de ORGANIZAR, que são os seguintes: estabelecer as bases de; arrumar de determinado modo; colocar em certa ordem.” –Renato Rocha Souza
  • 16. Entender é… Organizar ideias e conceitos, atribuindo uma ordem, classificando os mesmos.
  • 19. Entender é… Organizar ideias e conceitos, atribuindo uma ordem, classificando os mesmos.
  • 20. Nome é… Palavra ou locução com que se designa uma classe de coisas, pessoas, animais, um lugar, um acidente geográfico, um astro etc.
  • 21. “Existem duas coisas difíceis em computação: invalidação de cache e nomear coisas.” –Phil Karlton
  • 23. Nomes são descobertos! Sem nome Sem sentido Honesto Honesto e Completo Faz o que o nome diz Intenção ↪ ↪ ↪ ↪ ↪ ↪ Abstração de domínio
  • 24. Nomes são descobertos! Sem nome Sem sentido Honesto Honesto e Completo Faz o que o nome diz Intenção ↪ ↪ ↪ ↪ ↪ ↪ Abstração de domínio @arlobelshee
  • 25. var rootJquery, // A simple way to check for HTML strings // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) // Shortcut simple #id case for speed rquickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]+))$/, init = jQuery.fn.init = function( selector, context, root ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if (!selector) { return this; } // Method init() accepts an alternate rootjQuery // so migrate can support jQuery.sub (gh-2101) root = root || rootjQuery; // Handle HTML strings if (typeof selector === "string") { if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else { match = rquickExpr.exec( selector ); } … // HANDLE: $(expr, $(...)) } else if (!context || context.jquery) { return (context || root).find(selector); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor(context).find(selector); } // HANDLE: $(DOMElement) } else if (selector.nodeType) { this[0] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready } else if (isFunction(selector)) { return root.ready !== undefined ? root.ready(selector) : // Execute immediately if ready is not present selector(jQuery); } return jQuery.makeArray(selector, this); }; // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { context = context instanceof jQuery ? context[0] : context; // Option to run scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge(this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true )); // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { for (match in context) { // Properties of context are called as methods if possible if (isFunction(this[match])) { this[match](context[match]); // ...and otherwise set as attributes } else { this.attr(match, context[match]); } } } return this; // HANDLE: $(#id) } else { elem = document.getElementById(match[2]); if (elem) { // Inject the element directly into the jQuery object this[0] = elem; this.length = 1; } return this; }
  • 26. var rootJquery, // A simple way to check for HTML strings // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) // Shortcut simple #id case for speed rquickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]+))$/, init = jQuery.fn.init = function( selector, context, root ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if (!selector) { return this; } // Method init() accepts an alternate rootjQuery // so migrate can support jQuery.sub (gh-2101) root = root || rootjQuery; // Handle HTML strings if (typeof selector === "string") { if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else { match = rquickExpr.exec( selector ); } … // HANDLE: $(expr, $(...)) } else if (!context || context.jquery) { return (context || root).find(selector); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor(context).find(selector); } // HANDLE: $(DOMElement) } else if (selector.nodeType) { this[0] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready } else if (isFunction(selector)) { return root.ready !== undefined ? root.ready(selector) : // Execute immediately if ready is not present selector(jQuery); } return jQuery.makeArray(selector, this); }; // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { context = context instanceof jQuery ? context[0] : context; // Option to run scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge(this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true )); // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { for (match in context) { // Properties of context are called as methods if possible if (isFunction(this[match])) { this[match](context[match]); // ...and otherwise set as attributes } else { this.attr(match, context[match]); } } } return this; // HANDLE: $(#id) } else { elem = document.getElementById(match[2]); if (elem) { // Inject the element directly into the jQuery object this[0] = elem; this.length = 1; } return this; }
  • 27. jQuery( selector [, context ] ) jQuery( element ) jQuery( elementArray ) jQuery( object ) jQuery( selection ) jQuery() jQuery( html [, ownerDocument ] ) jQuery( html, attributes ) jQuery( callback )
  • 28. var rootJquery, // A simple way to check for HTML strings // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) // Shortcut simple #id case for speed rquickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]+))$/, init = jQuery.fn.init = function( selector, context, root ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if (!selector) { return this; } // Method init() accepts an alternate rootjQuery // so migrate can support jQuery.sub (gh-2101) root = root || rootjQuery; // Handle HTML strings if (typeof selector === "string") { if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else { match = rquickExpr.exec( selector ); } … // HANDLE: $(expr, $(...)) } else if (!context || context.jquery) { return (context || root).find(selector); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor(context).find(selector); } // HANDLE: $(DOMElement) } else if (selector.nodeType) { this[0] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready } else if (isFunction(selector)) { return root.ready !== undefined ? root.ready(selector) : // Execute immediately if ready is not present selector(jQuery); } return jQuery.makeArray(selector, this); }; // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { context = context instanceof jQuery ? context[0] : context; // Option to run scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge(this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true )); // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { for (match in context) { // Properties of context are called as methods if possible if (isFunction(this[match])) { this[match](context[match]); // ...and otherwise set as attributes } else { this.attr(match, context[match]); } } } return this; // HANDLE: $(#id) } else { elem = document.getElementById(match[2]); if (elem) { // Inject the element directly into the jQuery object this[0] = elem; this.length = 1; } return this; } Sem nome!
  • 29. var handleHTMLStrings = function (selector, context, root) { if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { // ... // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { // ... } return this; // HANDLE: $(#id) } else { // ... } // HANDLE: $(expr, $(...)) } else if (!context || context.jquery) { // ... // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { // ... } } Sem sentido!
  • 30. var handleHTMLStrings = function (selector, context, root) { if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { // ... // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { // ... } return this; // HANDLE: $(#id) } else { // ... } // HANDLE: $(expr, $(...)) } else if (!context || context.jquery) { // ... // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { // ... } }
  • 31. var handleHTMLStringsAndElementIds = function (selector, context, root) { if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { // ... // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { // ... } return this; // HANDLE: $(#id) } else { // ... } // HANDLE: $(expr, $(...)) } else if (!context || context.jquery) { // ... // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { // ... } } Honesto!
  • 32. var handleHTMLStringsAndElementIds = function (selector, context, root) { if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { // ... // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { // ... } return this; // HANDLE: $(#id) } else { // ... } // HANDLE: $(expr, $(...)) } else if (!context || context.jquery) { // ... // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { // ... } }
  • 33. var handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root) { if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [null, selector, null]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { // ... // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { // ... } return this; // HANDLE: $(#id) } else { // ... } // HANDLE: $(expr, $(...)) } else if (!context || context.jquery) { // ... // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { // ... } } Honesto e completo!
  • 35. handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root) handleHTMLStrings = function (selector, context, root)
  • 36. handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root) handleHTMLStrings = function (selector, context, root) handleElementIds = function (selector, context, root)
  • 37. handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root) handleHTMLStrings = function (selector, context, root) handleElementIds = function (selector, context, root) handleCSSSelectors = function (selector, context, root)
  • 38. handleHTMLStringsAndElementIdsAndCSSSelectors = function (selector, context, root) handleHTMLStrings = function (selector, context, root) handleElementIds = function (selector, context, root) handleCSSSelectors = function (selector, context, root)
  • 39. var handleHTMLStrings = function (match, context, root) { // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { context = context instanceof jQuery ? context[0] : context; // Option to run scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge(this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true )); // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { for (match in context) { // Properties of context are called as methods if possible if (isFunction(this[match])) { this[match](context[match]); // ...and otherwise set as attributes } else { this.attr(match, context[match]); } } } return this; } } } Sem sentido?
  • 40. Características de bons nomes de métodos • Use verbos*; • Sem abreviações; • Conciso (mas, não muito!); • Use perguntas quando o método retornar um boolean (isEmpty(), canDo()); • Não use “And” e “Or” nos seus nomes; • Não deixe o nome redundante com o argumento
 ($list->addItem($item)); • Não deixe o nome redundante com quem chama
 ($list->addToList($item));
  • 41. var buildFromHTMLString = function (match, context, root) { // Match html or make sure no context is specified for #id if (match && (match[1] || !context)) { // HANDLE: $(html) -> $(array) if (match[1]) { context = context instanceof jQuery ? context[0] : context; // Option to run scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge(this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true )); // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { for (match in context) { // Properties of context are called as methods if possible if (isFunction(this[match])) { this[match](context[match]); // ...and otherwise set as attributes } else { this.attr(match, context[match]); } } } return this; } } }
  • 42. Temos um bom nome? • Use verbos* √ • Sem abreviações √ • Conciso (mas, não muito!) √ • Use perguntas quando o método retornar um boolean (isEmpty(), canDo()) √ • Não use “And” e “Or” nos seus nomes √ • Não deixe o nome redundante com o argumento √ • Não deixe o nome redundante com quem chama √
  • 43. var fromHTMLString = function (match, context) { // HANDLE: $(html) -> $(array) if (match[1]) { context = context instanceof jQuery ? context[0] : context; // Option to run scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge(this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true )); // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { for (match in context) { // Properties of context are called as methods if possible if (isFunction(this[match])) { this[match](context[match]); // ...and otherwise set as attributes } else { this.attr(match, context[match]); } } } return this; } }
  • 44. var fromHTMLString = function (match, context) { // HANDLE: $(html) -> $(array) if (match[1]) { context = context instanceof jQuery ? context[0] : context; // Option to run scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge(this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true )); // HANDLE: $(html, props) if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) { for (match in context) { // Properties of context are called as methods if possible if (isFunction(this[match])) { this[match](context[match]); // ...and otherwise set as attributes } else { this.attr(match, context[match]); } } } return this; } }
  • 45. Características de bons nomes de variáveis • Sem abreviações; • Conciso (mas, não muito!); • Use perguntas quando o método retornar um boolean (isEmpty, canDo); • Não use “And” e “Or” nos seus nomes;
  • 46. var fromHTMLString = function (source, context) { if (source) { context = context instanceof jQuery ? context[0] : context; var runScriptsForBackCompat = true var isNode = context && context.nodeType; var contextDocument = isNode ? context.ownerDocument || context : document; jQuery.merge(this, jQuery.parseHTML(source, contextDocument, runScriptsForBackCompat)); var isSingleTagWithoutAttributes = rsingleTag.test(source) var isAttributesSuperSet = jQuery.isPlainObject(context); if (isSingleTagWithoutAttributes && isAttributesSuperSet) { for (attributeName in context) { // Properties of context are called as methods if possible if (isFunction(this[attributeName])) { this[attributeName](context[attributeName]); // ...and otherwise set as attributes } else { this.attr(attributeName, context[attributeName]); } } } return this; } }
  • 47. var fromHTMLString = function (source, context) { if (source) { context = context instanceof jQuery ? context[0] : context; var runScriptsForBackCompat = true var isNode = context && context.nodeType; var contextDocument = isNode ? context.ownerDocument || context : document; jQuery.merge(this, jQuery.parseHTML(source, contextDocument, runScriptsForBackCompat)); var isSingleTagWithoutAttributes = rsingleTag.test(source) var isAttributesSuperSet = jQuery.isPlainObject(context); if (isSingleTagWithoutAttributes && isAttributesSuperSet) { for (attributeName in context) { // Properties of context are called as methods if possible if (isFunction(this[attributeName])) { this[attributeName](context[attributeName]); // ...and otherwise set as attributes } else { this.attr(attributeName, context[attributeName]); } } } return this; } }
  • 48. Características de bons nomes de classes • Use substantivos e adjetivos*; • Não use muitos adjetivos (AbstractFactoryPatternBase); • Não use “Manager”, “Helper” e “Data” nos seus nomes; • Não use Sufixos do seu namespace (Service, Factory, Iterator) • Evite usar “er”, “or”, “tion”, “sion” (ObjectFinder, DataProcessor, Conversion, DataManipulation)
  • 49. –Chris Oldwood “So, a "DateTimeProvider", that's basically just a clock, right?”
  • 50. Características de bons nomes de variáveis Service is the new Enzo
  • 51. var HTMLCreationContext = function (elementOrAttributes) { this.elementOrAttributes = elementOrAttributes; } HTMLCreationContext.prototype = { isNode: function () { return (this.elementOrAttributes && this.elementOrAttributes.nodeType); }, getOwnerDocument: function () { if (this.isNode) { return this.elementOrAttributes.ownerDocument || this.elementOrAttributes; } return document; }, getAttributesSuperSet: function () { if (jQuery.isPlainObject(this.elementOrAttributes)) { return this.elementOrAttributes; } return {}; }, getMergeContext: function () { if (this.elementOrAttributes instanceof jQuery) { return this.elementOrAttributes[0]; } return this.elementOrAttributes; } }
  • 52. var HTMLCreationContext = function (elementOrAttributes) { this.elementOrAttributes = elementOrAttributes; } HTMLCreationContext.prototype = { isNode: function () { return (this.elementOrAttributes && this.elementOrAttributes.nodeType); }, getOwnerDocument: function () { if (this.isNode) { return this.elementOrAttributes.ownerDocument || this.elementOrAttributes; } return document; }, getAttributesSuperSet: function () { if (jQuery.isPlainObject(this.elementOrAttributes)) { return this.elementOrAttributes; } return {}; }, getMergeContext: function () { if (this.elementOrAttributes instanceof jQuery) { return this.elementOrAttributes[0]; } return this.elementOrAttributes; } }
  • 53. var fromHTMLString = function (source, context) { if (source) { var creationContext = new HTMLCreationContext(context); var runScriptsForBackCompat = true jQuery.merge(this, jQuery.parseHTML( source, creationContext.getOwnerDocument(), runScriptsForBackCompat )); var isSingleTagWithoutAttributes = rsingleTag.test(source) if (isSingleTagWithoutAttributes) { var attributes = creationContext.getAttributesSuperSet(); for (attributeName in attributes) { // Properties of context are called as methods if possible if (isFunction(this[attributeName])) { this[attributeName](context[attributeName]); // ...and otherwise set as attributes } else { this.attr(attributeName, context[attributeName]); } } } return this; } }
  • 54.
  • 55. Concluindo… 1. Procure por lugares com mais de um nível de identação 2. Extraia e dê nome para o que fizer sentido 3. Descreva o que o método realmente faz, sem vergonha, seja honesto! 4. Vá diminuindo o nome do método extraindo suas responsabilidades 5. Excesso de métodos privados para um dado contexto: Uma nova classe! 6. Procure na documentação ou fale com um amiguinho para descrever
 o problema de domínio resolvido 7. Seja feliz!