Casi todos los programadores de PHP hemos partido de una pesadilla de código así:
Código :
<h1>Usuarios</h1> <select name=”users”> <?php $sql = "SELECT first_name, last_name from users"; $q = mysql_query($sql); while ($user = mysql_fetch_obj($)): ?> <option <? if (isset($_GET[‘user_id’]) && $_GET[‘user_id’] == $user->id): ?> selected=”selected” <?php endif; ?>><?= $user->first_name ?> <?= $user->last_name ?></option> <?php endwhile ?> </select>
Quizás hasta nos llegamos a sentir orgullosos de mezclar PHP + MySQL + HTML ¡En menos de 10 líneas de código!
Pero ser un buen programador no consiste en cuán críptico e indescifrable sea tu código ni cuántas instrucciones puedas crear en una sola línea. Vean el siguiente ejemplo, extraído de un framework PHP:
Código :
return '<li class="admin_action_delete">'.link_to(__($params['label'], array(), 'admin'), $this->getUrlForAction('delete'), $object, array('method' => 'delete', 'confirm' => !empty($params['confirm']) ? __($params['confirm'], array(), 'admin') : $params['confirm'])).'</li>';
(He visto ejemplos mucho peores, pero como suele pasar, ahora que necesito uno, no consigo).
Predicción de comentario:
programador :
Duilio, me decepcionas, ¿Dices ser un super programador pero no puedes entender esa línea de código? Es un helper que crea una lista con un link a una ruta para eliminar un item y tiene la opción de que se requiera confirmar si se desea eliminar o no. Además es multi idioma y…
Pufff… ¿Y cuanto tiempo te llevó analizar todo eso? ¿Cuánto tiempo va a pasar hasta que necesites volver a leer esa línea nuevamente y tengas que analizarla otra vez porque se te olvidó lo que hacía?
Un código se escribe una vez, pero se tiene que leer luego muchas veces
Cada minuto que no quisiste gastar separando un poco tu código para que fuese más legible, serán uno o dos minutos que gastarás tratando de entenderte a ti mismo cuando requieras hacer un cambio o corregir un bug.
Hay un dicho famoso que dice “programa como si la persona que va a mantener tu código fuese un asesino en serie que sabe donde vives”.
Toma el tiempo que a ti mismo te va a costar entender lo que hiciste y multiplícalo por 5: ese es el tiempo que tus colegas van a perder leyendo tu código, y van a odiarte, no van a invitarte a sus fiestas ni a presentarte a sus amigas y ruega a Dios que alguno no sea un psicópata capaz de preparar ricino y ponerlo en tu café.
Pero ahora tenemos MVC y toda esta pesadilla de código espagueti terminó para siempre ¿No?
Lamentablemente, no. Ahora se ha vuelto un poco más sutil, estoy cansado de ver código como éste:
Código :
<?php //Controlador $users = User::all(); $selected_user = Input::get(‘user_id’, null); return $View::make(‘users/list’, compact($users, $selected_user));
Código :
<!-- Vista --> <select name="users"> <? foreach ($users as $user): ?> <option <? if ($selected_user == $user->id): ?> selected=”selected” <?php endif; ?> value=”<?= $user->id ?>”><?= $user->first_name ?> <?= $user->last_name ?></option> <? endforeach; ?> </select>
Hablando en general, los programadores aprendieron el concepto de separar la lógica del controlador de la vista, pero muy pocos realmente saben encapsular su lógica dentro de la capa del modelo.
En el ejemplo anterior el controlador está muy bien. Es la vista lo que está fallando.
Supongamos que luego necesitamos un filtro por usuarios en otros módulos de nuestra aplicación.
¿Qué harán? ¿Copiarán y pegaran el mismo código? No. Crearán una vista llamada partials/select_users.php de manera que puedan sólo incluirla cada vez que necesiten el select? Mejor, pero no.
¿Qué pasa si el cliente pide que el nombre completo del usuario (first_name + last_name) se complemente con un “title” como Dr. o Ing.? Tendrías que modificar varias vistas de tu código.
¿Qué pasa si en un módulo en específico necesitas imprimir una lista de usuarios (<ul> <li>) o radios en vez de usar un select? Tendrías que duplicar la lógica de negocios (imprimir una lista de usuarios por nombre completo) para cubrir los cambios en el HTML.
Todo esto trae esfuerzos adicionales que podrían evitarse desde un principio. Insisto: cada minuto “ahorrado” en un inicio serán minutos desperdiciados luego.
Veamos cómo mejorar el ejemplo:
1. Si estás trabajando con un framework que incluya un ORM como Ruby on Rails o Laravel en PHP y muchos otros
... seguramente puedes crear propiedades “virtuales”. En Laravel:Código :
<?php // Modelo User.php public function getFullNameAttribute() { retrun $this->first_name . ' ' . $this->last_name; }
Aunque tu columna “full_name” no exista en la tabla “users” gracias al código anterior podrás acceder a ella como si existiera, siempre que trabajes con tu modelo User:
Código :
<?php $user->full_name ?>
2. Pasa la lógica para generar una lista de usuarios igualmente al modelo:
Código :
public static function listByName() { $users = User::all(); $list = array(); foreach ($users as $user) { $list[$user->id] = $user->full_name; } return $list; }
De forma que en cualquier lugar de tu aplicación donde lo necesites podrás retornar la lista de usuarios por nombre simplemente haciendo lo siguiente:
Código :
$user = User::listByName()
3. Utiliza el poder de tu framework (Helpers, etc.)
En Laravel, así como en muchos otros frameworks, hay utilidades que te permiten hacer tareas comunes, por ejemplo en Laravel no necesitas generar un select manualmente, por lo que puedes hacer lo siguiente:Código :
<?php HTML::select('users', User::listByName(), $selected_user) ?>
¡Lee la documentación de tu framework favorito y aprende qué puede hacer por ti!
¿No usas ningún framework?
Probablemente seas de esas personas super interesantes que prefieren salir a cazar su propia comida en vez de ir al automercado, en ese caso, no es muy difícil crear pequeños componentes que faciliten tus tareas comunes:Código :
function options($options, $selected = null) { $html = ""; foreach ($options as $idx => $value) { $select = $selected == $idx ? ' selected="selected"' : ''; $html .= '<option value="' . $idx . '"' . $select . '>' . $value . '</option>'; } return $html; }
Código :
<h1>Usuarios</h1> <select name="users"> <?php $selected_user = isset ($_GET['user']) ? $_GET['user'] : null; options(user_list_by_name(), $selected_user); ?> </select>
Algunos consejos a tener en cuenta:
Primero piensa en legibilidad y luego en optimización: el código espagueti presentado al inicio del post probablemente se ejecuta unos milisegundos más rápido que las otras opciones más elaboradas.
Hoy en día tenemos servidores MUY potentes, y siempre es mucho más barato comprar un poco más de memoria RAM (en caso de que haga falta) que contratar a otro programador. La diferencia de tareas tan sencillas como un IF o un ciclo no será notable. Piensa en optimizar, pero primero en optimizar el tiempo humano de correción, expansión y mantenimiento del proyecto, luego en el tiempo de procesamiento.
Si este post te comienza a volver improductivo, ignóralo por ahora, sigue trabajando en la forma en que te permita codificar más rápido y cumplir tus compromisos, poco a poco a medida que sientas la necesidad volverás a recordar los consejos acá descritos y empezarás a aplicarlos en tus próximos proyectos. No tienes que cambiar radicalmente de un día para otro.
Mi intención no es sólo enseñarles Laravel sino hacerles mejores programadores en general. Un proyecto con Rails no garantiza un código limpio, así, un proyecto hecho a pie en PHP no tiene que ser un desastre. Unos lenguajes y frameworks te ayudan a escribir mejor código que otros y en esto PHP no tiene fama de ser precisamente el mejor, sin embargo al final depende de cada programador.
En orden de importancia para mí sería: Programador > Framework > Lenguaje.
Recuerden seguirme en Twitter @sileence para poder notificarles de más artículos de programación en general y Laravel.
También recomiendo que aprovechen la promoción de mejorando.la/navidad, en el 2014 se viene un curso de Laravel donde espero poder compartir más con ustedes y ampliar los conocimientos que he ido impartiendo acá en Cristalab
¡Saludos!
¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.
Por Lucas el 11 de Diciembre de 2013
Por Maikel el 12 de Diciembre de 2013
Código :
Cada vez que veo un clase llamada HTML, ruego porque el infierno exista y se llene de autores de esas clases.
Por Duilio el 12 de Diciembre de 2013
Maikel :
Código :
Cada vez que veo un clase llamada HTML, ruego porque el infierno exista y se llene de autores de esas clases.
Why?
Por cierto en Laravel es Form::select en vez de HTML::select, bueno esto es un artículo más que un tutorial de Larale de cualquier forma.
Pero en Laravel sí hay una clase HtmlBuilder y FormBuilder que se encargan de generar HTML. Y Tienen sus respectivos Facades com HTML y Form
¿Qué es lo que te molesta de todo eso?
Por José Pérez el 12 de Diciembre de 2013
En fin agradezco este tipo de post porque ahora trabajo fuertemente en ser mejor programador.
Por guscro el 12 de Diciembre de 2013
Saludos
Por Dientuki el 12 de Diciembre de 2013
"Primero piensa en legibilidad y luego en optimización"
La mayor optimizacion para "backend" es algun sistema de cache (Varnish, wp-cache, drupal tambien tiene uno... y si wordpress tiene un sistema de cache no hay excusas para que tu framework no lo tenga). Con tu sitio cacheado, no importa si tu codigo es bueno o malo (o por lo menos no importa tanto), siempre sera servido rapido.
Lo malo de cachear, es que no siempre se puede o a veces se complejiza demaciado.
Por Duilio el 12 de Diciembre de 2013
Por Duilio el 12 de Diciembre de 2013
guscro-blog :
Saludos
La manera más ortodoxa como mencionas sería obtener la data en el controlador y pasarla a la vista como una variable. La vista no debería saber si quiera de donde provino la data, sólo usarla y ya.
Comunicar la vista con el modelo directamente es un "atajo" a veces es práctico porque disminuye muchas líneas en el controlador, sobretodo si tienes muchas vistas y sub-vistas que incluyen data dinámica por todas partes, como fue mi caso cuando trabajé en una red social con Laravel.
Los ejemplos de este post son sencillos, no contemplan inyección de dependencias y otros patrones, pero si provienes del ejemplo 2 (no digamos que nadie ya siga en el ejemplo 1) será un gran buff que permitirá que tus proyectos sean mucho más ordenados, limpios, reusables y... divertidos
Quizás luego a petición del público () podría escribir "mejora tus habilidades como programador, parte 2" y tocar más temas de este tipo.
Por Aoyama el 12 de Diciembre de 2013
No estaría de más tocar el tema con algún otro patrón de diseño en mente si planean hacer estos tutoriales un poco más educativos. Por cierto, ¿cuándo hablan de MVC hablan del original o de cual de todas sus variantes?
BTW: Ese ajuste automático que hace la caja de texto de comentario es bastante molesto cuando lo hace con cada click que das (Win8 + Firefox 25.0.1)
Por Duilio el 13 de Diciembre de 2013
Aoyama :
Digamos el concepto común que comparten todos los frameworks MVC: la idea de dividir el código en 3 capas. 3 capas a mí me parece muy poco pero luego igual la gente apenas si usa 2 y terminan mezclando siempre lógica de negocias en los controladores y las vistas, por eso el motivo del artículo.
Aoyama :
¿Qué otros patrones sugieres?
Por zamarrong el 13 de Diciembre de 2013
Por Duilio el 13 de Diciembre de 2013
zamarrong-blog :
A mi me encanta usar "Named routes" me parece que es lo mejor. route() o URL::route()
Por Aoyama el 13 de Diciembre de 2013
Duilio :
Aoyama :
Digamos el concepto común que comparten todos los frameworks MVC: la idea de dividir el código en 3 capas. 3 capas a mí me parece muy poco pero luego igual la gente apenas si usa 2 y terminan mezclando siempre lógica de negocias en los controladores y las vistas, por eso el motivo del artículo.
Aoyama :
¿Qué otros patrones sugieres?
Publicador-Subscriptor, Mediator, Singleton, Observer, algunos de los cuales, MVC tomó fundamento si mal no recuerdo.
Por DevCH el 13 de Diciembre de 2013
Por Duilio el 13 de Diciembre de 2013
DevCH :
Yo también creé mi propio framework, pero eventualmente por los clientes terminé usando frameworks comerciales o abiertos (lo exigen). Creo que si quieres tener tu propio framework tienes dos caminos: o tener tu propia agencia y trabajar con lo que sea que quieras (en este caso tu propio fw) o liberarlo.
Por zamarrong el 13 de Diciembre de 2013
Por Duilio el 13 de Diciembre de 2013
zamarrong-blog :
¿Cuál búsqueda en donde?
A decir verdad a mí me funciona de maravillas tu web.
¿La hiciste tú solo con Laravel?
Un tip muy importante: Si tu formulario cambia el estado de la aplicación (guarda o elimina) usa POST, pero si no (solo filtra, busca) usa GET
Por Dano el 13 de Diciembre de 2013
Mi terapista me dijo que esos codigos amontonados no existen, no existen, no............. funciones de 300 lineas y 8 niveles de IF anidados son una fantasia como los unicornios.
*se va a una esquina, se arrincona y toma sus pastillas
Por zamarrong el 13 de Diciembre de 2013
Por Duilio el 13 de Diciembre de 2013
Dano :
Mi terapista me dijo que esos codigos amontonados no existen, no existen, no............. funciones de 300 lineas y 8 niveles de IF anidados son una fantasia como los unicornios.
*se va a una esquina, se arrincona y toma sus pastillas
Sí... En Cristalab, tú y Maikel me ayudaron mucho cuando estaba comenzando y quería hacer mi propio framework, etc. Muy agradecido *
*PD: Aunque ahora los superé a ambos y deben reconocerme como su nuevo lider
Por Duilio el 13 de Diciembre de 2013
zamarrong-blog :
Oh! Genial. Va quedando muy bien... ¿Empezaste con mis tutos o de otra forma?
Para las rutas Laravel es genial, no tengas miedo de definir cuantas rutas te hagan falta.
Pero para búsqueda, filtros, paginación en mi opinión lo mejor es usar parámetros GET.
Yo sólo haría rutas amigables para categorias / subcategorias, detalle del producto, etc.. Pero para busqueda avanzada con muchos parámetros usa GET...
Por andresVergara el 18 de Diciembre de 2013
Saludos
Por leviatanMX el 19 de Diciembre de 2013
Por leviatanMX el 19 de Diciembre de 2013
https://www.youtube.com/watch?v=8m7wsUS1tJ0
Por heyluis el 30 de Diciembre de 2013
Por kakashi2000 el 02 de Enero de 2014
Me gustaria que me ayudaras a cumplir mis metas de ser un buen desarrollador, mejorando mi codigo y mi manera de pensar en desarrollar.
Gracias.
Por Aoyama el 02 de Enero de 2014
kakashi2000 :
Me gustaria que me ayudaras a cumplir mis metas de ser un buen desarrollador, mejorando mi codigo y mi manera de pensar en desarrollar.
Gracias.
Aprende metodologías de desarrollo, usabilidad, interacción y buenas prácticas. Los frameworks pasan, las herramientas también.
Por sisas. el 17 de Enero de 2014
Por Aoyama el 17 de Enero de 2014
sisas.-blog :
No necesariamente, pero tampoco es bueno depender al 100% de un framework determinado.
Por Duilio el 17 de Enero de 2014
Aoyama :
sisas.-blog :
No necesariamente, pero tampoco es bueno depender al 100% de un framework determinado.
Si el framework es open source de alguna manera tienes el control del código, en tal caso este consejo sólo aplica para frameworks como Phalcon PHP que tiene buenas críticas pero está escrito en C entonces pierdes el control del código fuente.
Yo muchas, muchas veces he entrado a revisar el código de Laravel y otros frameworks con los que he trabajado...
Por ziette el 14 de Marzo de 2014
Por DevCH el 16 de Marzo de 2014
Duilio :
DevCH :
Yo también creé mi propio framework, pero eventualmente por los clientes terminé usando frameworks comerciales o abiertos (lo exigen). Creo que si quieres tener tu propio framework tienes dos caminos: o tener tu propia agencia y trabajar con lo que sea que quieras (en este caso tu propio fw) o liberarlo.
Hasta ahora no he tenido ningún cliente que me pida que utilice un determinado FW, me piden que les haga algo para resolver algún problema o cosas así pero no se meten a ver en que lo hago. Sin embargo, como profesional escojo la mejor herramienta y si puedo utilizar mi propio FW lo utilizo, sino, busco lo mejor para el cliente de todas maneras.
Por Carlos Salazar el 24 de Marzo de 2014
Por Moises V el 06 de Mayo de 2014
Por Shirley C.C. el 02 de Septiembre de 2014
Tus explicaciones son excelentes.
Por leviatanMX el 17 de Abril de 2015
Carlos Salazar :