Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Evitar efectos colaterales

10/26
Recursos

Debemos analizar muy bien nuestro código para evitar efectos colaterales y evitar que nuestro código deje de funcionar. Un consejo de nuestro profesor en esta clase: No uses variables globales.

Aportes 53

Preguntas 3

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Para evitar efectos colaterales, les recomiendo el curso de scope y clousures en js, si bien está hecho para JS, se puede entender la importancia de mantener la integridad de la data, otorgando ámbito a las variables.

Lo mejor es no usar estas variables globales, sin embargo, a veces son necesarias, por ejemplo en casos donde tienes un flag y necesitas evaluar ciertas condiciones, en ese caso el flag debe ser global, pero la diferencia es que tu sabes de entrada que ese flag va a cambiar su valor, en el ejemplo de esta clase no tenías ni idea de que iba a cambiar, ahí está la diferencia

Es importante conocer las características del lenguaje de programación con el que se está codificando. Por ejemplo, yo en realidad no conozco PHP, pero en otros lenguaje de programación compilados y orientados a objetos, existe algo llamado el ámbito de las variables, concepto que evita (o busca evitar) lo que conocemos cómo código espagueti.
Hablando estrictamente de las variables globales, si bien estas deben ser usadas al mínimo, siguen siendo un recurso que es importante tener en cuenta, no son prohibidas, solamente hay que saber usarlas, y por supuesto: evitar que se modifiquen una vez asignadas, por ejemplo las variables de inicio de sesión que necesitaremos para validar el acceso por roles a distintas partes de nuestros sistemas.
Un par de links al respecto:
Ámbito
Espagueti
Variables globales

Nota Clase: algo que sucede algo más allá del código del código que se esta leyendo, un ejemplo de esto es la modificación de una variable global. Mas preciso es realizar cosas que no van el la función, es decir que la función no haga mas de una cosa, lo que indica su nombre.

Reto se usa mismo nombre de variable para asignar el valor normalizado, esto inducirá side effects.

$empl_num = str_replace("?", 'Ñ', $empl_num);,

Reto4e no entendí bien, pero imagino que la variable manzanas al ser private en la clase Manzano, siempre retornará un array vacío.

Reto4b no encontre side effects.

Reto4 no encontre side effects.

Reto4d El hecho de extender la función UnderlingInterface, y exponer el mismo nombre de función en distintas clases de manera global generará side effects.

Recto4c Similar al reto 4d, se tiene el mismo nombre de función que tiene scope global en distintas clases.

Reto

  • Se puede usar una función para extraer los valores de cada row. En esta función podríamos usar destructuring al momento de asignar el resultado de la misma en nuevas variables
  • str_replace se usa en diferentes lugares, con parámetros muy similares. Esto se podría reemplazar con una función en la cual solamente enviamos el valor que queremos actualizar.
  • La condición que evalua $hora y $trabajo se puede extraer,
    • Dentro de esta condición, a las variables horae y horas se les puede dar un nombre más descriptivo (horaentrada, horasalida)

Reto 4
La clase Orden es un ejemplo de código no modularizado, ya que contiene varios métodos que podrían extraerse.

  • Los métodos load, save, update y delete podrían ser usados en diferentes lugares de la aplicación.
    • El hecho de que estos métodos estén en esta clase me da a entender que es posible que otras clases también cuenten con éstos métodos, lo que significaría que hay código duplicado. Si hay un bug en estos métodos, es muy probable que ese bug se encuentre esparcido en las demás clases que tienen estos métodos.

Reto 4b
El método process de la clase ProjectManagement cuenta con una condición por cada tipo de parametro que recibe, y dependiendo de éste ejecuta cierto método exclusivo de cada clase. Por lo que si en un futuro se crea una nueva clase, el método process tendrá que ser modificado.

Las clases Programmer y Tester podrían hacer uso de una interfaz que cuente con un método work por ejemplo, y cada clase implementaría ese método a sus necesidades.

Al realizar este cambio, el método process quedaría más limpio ya que podría llamar un método que todas la clases tienen en común, en lugar de evaluar la clase del parámetro que recibe y con base en eso ejecutar el método correspondiente


Reto 4c
La clase Animal cuenta con una función llamada fly sin embargo, no todos los animales pueden volar.
La clase Dog, al heredar de la clase Animal, abre la posibilidad de que se pueda a llamar este método desde clase Dog, por lo que el código sobreescribe el método heredado para evitar que éste se pueda ejecutar, lo cual no me parece lo más adecuado.
Esto se puede resolver removiendo el método fly de la clase Animal, y creando una nueva clase Ave que herede de Animal y que cuente con su propio método fly. De esta manera, las clases que hereden de **Animal **en un futuro no tendrán el método **fly **disponible, y las clases que hereden de Ave sí tendrán el método fly disponible,


Reto 4d
La clase Consultant no implementa el método collate. Si una clase no implementa todos los métodos de la interfaz de la cual extiende, entonces no debería de extender de esa interfaz.


Reto 4e
La clase ContadorDeManzanas podría ser un poco más generica y de este modo sería reutilizable.
Actualmente, si queremos obtener el numero de manzanas de un manzano, tenemos que crear una instancia de ContadorDeManzanas.
Si tuvieramos 100 instancias de Manzano, y quisieramos obtener el numero de manzanas de cada uno de ellos, tendríamos que crear 100 instancias de ContadorDeManzanas, lo cual no me parece eficiente.

resumen patatero, nunca usar variables globales y tener especial cuidado al alcance o scope de las mismas en su contexto especifico de uso

Reto 4a - No veo muy claro que se puede mejorar.

Reto 4b -

<?php
    class Programmer
    {
        public function actionCoding()
        {
            return 'coding';
        }
    }
    class Tester
    {
        public function actionTesting()
        {
            return 'testing';
        }
    }
    class ProjectManagement
    {
        public function printAction($member)
        {
            if ($member instanceof Programmer) {
                $member->actionCoding();
            } elseif ($member instanceof Tester) {
                $member->actionTesting();
            };
            throw new Exception('Invalid input member');
        }
    } 

Reto 4c - Creo que la función Fly ya existe en la clase Animal y al extenderlo en la clase Dog no hace falta declarar la función nuevamente en Dog ya que ha sido heredada de Animals.

<?php
    class Animal
    {
        public function fly()
        {
        }
    }

    class Dog extends Animal
    {
	fly(){
            if (! $this->hasWings) {
                throw new Exception;
	}
            }
    }

Reto 4d - Algo confundido en esta 🤔

Reto 4e - Solo vi un error en el nombre de construct

    public function __construct(Manzano $manzano)

Algo que es de mucha ayuda para evitar efectos colaterales es hacer el código modular

Reto

  • Se puede usar una clase para traerse los datos de cada fila e identificar que es lo que hace especificamente o para que son esos datos

  • En el reemplazo del caracter se podría usar una función y así podemos reutilizar código, en este mismo punto se estan usando 2 tipos de estandares para definir variables

  • La condicion debería moverse a una funcion

  • Definicion explicita de que es hora, horas

Reto4

  • Algunas de las funciones tiene parametros por lo que al usarlas podrían estarse usando varibles globales

Reto4b

  • Escalabilidad, al agregar mas miembros la condición comenzaría a crecer por lo que podría usarse una interface e implementarla en cada clase para así retornar el ‘tipo de miebro’ que se esta procesando

Reto4c

  • Definicion de funcion innecesaria ya que no todos lo animales vuelan

  • No hay funciones que seten la información

Reto4d

  • No estoy seguro pero creo que seríaa mejor implementar la interface en la clase Lumbergh

Reto4e

  • El calculo de las manzanas debería hacerse en la funcion getManzanas de la clase Manzano para que en el contador de manzanas solo se obtenga el dato
No utilizar variables globales

Un efecto colateral es algo que sucede mas halla del codigo que se esta leyendo

Las funciones puras, que vienen del concepto de Programación Funcional. Evitan los side effects x)

Esto me recuerda a programación funcional en Javascript.

Esta clase nos lleva sin querer al maravilloso mundo de la programación funcional, donde las buenas practicas suceden sin que te des cuenta que las estas haciendo.

Efectos colaterales: Modificar variables que no pertenecen al alcance(scope) del bloque de codigo (if, functiones, etc) correspondiente.

Cada variable debe estar dentro de su alcance, sin verse afectada por fuera de dicho alcance.

Espero les guste mi humilde solución, también es posible utilizar interfaces.

    abstract class Action
    {
        abstract public function toDo();
    }

    class Programmer extends Action
    {
        public function toDo()
        {
            return 'coding';
        }
    }

    class Tester extends Action
    {
        public function toDo()
        {
            return 'testing';
        }
    }

    class ProjectManagement
    {
        public function process(Action $member)
        {
            return $member->toDo();
        }
    }

    $programmer = new Programmer();
    $test = new Tester();
    $newProject = new ProjectManagement();
    echo $newProject->process($programmer). PHP_EOL;
    echo $newProject->process($test) . PHP_EOL;
    echo $newProject->process('The instance must be an instance of Action');//Fatal Error

**reto.php: ** Puede usar funciones para sacar los valores del array y para imprimir en la pantalla.

**reto4e.php: ** No le veo que es lo que esta mal pero creo que se deberia cambiar ContadorDeManzanas a solo Contador por si se agrrega algun otro arbol de fruta.

**reto4b.php: ** Los “{” del “if” y “elseif” estan en la misma liena cuando todos los otros estan abajo.

**reto4.php: ** No se entiende bien porque todo esta junto. Mejoraria si huviera un espacio entre cada funcion.

**reto4d.php: ** Creo que en consultant no deberia llamar a collate si no va a regresar un valor

**reto4c.php: ** Lo mismo que el reto4b

  • En ej4.php (el que mostraste en la clase) estan las variables GLOBAL

  • En reto.php se podrian definir funciones para organizar mejor el codigo

  • En reto4.php seria mas entendible, si se pusieran saltos de linea e identacion

  • En reto4b.php y en reto4c.php algunas llaves estan debajo de la declaracion y en otras estan al lado, deberian estar al mismo nivel

  • En reto4d.php los nombres de los metodos no me parecen tan descriptivas

  • En reto4e.php el constructar esta mal declarado

En JavaScript se usa algo que se llama Closure que son la combinación del scope de una variable y las funciones con las que ella puede trabajar.

Los Closures sirven para tener “variables privadas”, o sea, para encapsular variables que no pueden ser modificadas directamente por otros objetos, sino solo por funciones pertenecientes al mismo ámbito.

Ejemplo:

// Código para hacer una alcancia

const moneyBox = (coins) => {
    var saveCoins = 0;
    saveCoins += coins;
    console.log(`MoneBox: $${saveCoins}`);
};

moneyBox(5); // 5
moneyBox(10); // 10

//  Código correcto 

const moneyBox = () => {
    var saveCoins = 0; // Esta pasa a ser una variable privada

    const countCoins = (coins) => {
        // aquí uso el closure porque en esta función accedo a una función exterior,
				// o sea a moneyBox con la variable savaCoins

        saveCoins += coins;
        console.log(`MoneBox: $${saveCoins}`);
    }
    return countCoins;
};

// Cuando retornamos countCoins esto no lo permite asignar a una variable
// y esta variable se convierte en un closure, o sea, una función y el entorno
// en que se creó esa función

let myMoneyBox = moneyBox();

// con myMoneyBox podemos acceder a saveCoins y a la funcion countCoins()

myMoneyBox(5); // 5
myMoneyBox(10); // 15

reto 4:

<?php
    class Order
    {
        public function getItems(){
            /*...*/
        }
        public function getItemCount(){
            /*...*/
        }
        public function addItem($item){
            /*...*/
        }
        public function deleteItem($item){
            /*...*/
        }
        public function calculateTotalSum(){
            /*...*/
        }
        
        
        public function printOrder(){
            /*...*/
        }
        public function showOrder(){
            /*...*/
        }

        public function load(){
            /*...*/
        }
        public function save(){
            /*...*/
        }
        public function update(){
            /*...*/
        }
        public function delete(){
            /*...*/
        }
    }


reto 4b:

<?php
    class Programmer
    {
        public function coding()
        {
            return 'coding';
        }
    }
    class Tester
    {
        public function testing()
        {
            return 'testing';
        }
    }
    class ProjectManagement
    {
        public function printActionMember($member)
        {
            if ($member instanceof Programmer) {
                $member->coding();
            } elseif ($member instanceof Tester) {
                $member->testing();
            };
            throw new Exception('Invalid input member');
        }
    }

reto 4c:

<?php
class Animal{
    public function flyingAnimal(){
        //...//
    }
}

class Dog extends Animal{
    public function flyingAnimal (){
        if (! $this->hasWings) {
            throw new Exception;
        } elseif($this->hasWings) {
            flyingAnimal();
        }
    }
}

reto 4d:

<?php

    interface UnderlingInterface
    {
        public function program();

        public function filetps();

        public function collectionAndCombination();
    }

    class Underling implements UnderlingInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collectionAndCombination()
        {
            return 'Collect and combine texts, information, and figures in proper order.';
        }
    }

    class Consultant implements UnderlingInterface
    {
        public function program()
        {
            return 'Outsource task to India';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collectionAndCombination()
        {
            return null;
        }
    }

    class Lumbergh
    {
        protected $underling;

        public function __construct(UnderlingInterface $underling)
        {
            $this->underling = $underling;
        }

        public function delegate()
        {
            $this->underling->program();
            $this->underling->filetps();
            $this->underling->collate();
        }
    }

y el reto 4 e no pude figurar que era lo que estaba por corregir

En el 4b- es necesario renombrar la función code y test

Hay que ser cuidadosos con las variables globales

Logré hacer un par de retos y aca muestro los resultados.

Reto4A.php

Reto4B.php

Reto4C.php


Reto4E.php

¿Cuál sería la buena práctica que reemplaza a usar variables globales? ¿Parámetros?

No se deben usar variables globales nunca.

En el reto4b el código no es escalable, seria mejor nombrar el método como “action” o cualquier otro nombre pero que sea igual en ambas clases (Seria bueno usar algún tipo de interface), ya que si no se realiza la modificación el if del método process va a ir creciendo a medida que existan mas roles

**De esto **

<?php
    class Programmer
    {
        public function code()
        {
            return 'coding';
        }
    }
    class Tester
    {
        public function test()
        {
            return 'testing';
        }
    }
    class ProjectManagement
    {
        public function process($member)
        {
            if ($member instanceof Programmer) {
                $member->code();
            } elseif ($member instanceof Tester) {
                $member->test();
            };
            throw new Exception('Invalid input member');
        }
    }

A esto

<?php
    class Programmer
    {
        public function action()
        {
            return 'coding';
        }
    }
    class Tester
    {
        public function action()
        {
            return 'testing';
        }
    }
    class ProjectManagement
    {
        public function process($member)
        {
           try {
	          $member->action();
           } catch (\Exception $e) { 
             throw new Exception('Invalid input member');  
          }	
        }
    }

Que cosa importante entender bien esto, al principio no le daba importancia hasta cometer varios errores y empezar a tenerlo en cuenta 😓

Se debe hacer un analisis muy bien de lo que se quiere hacer, para lograr tener las variables necesarias en nuestros metodos y asi evitar los efectos colaterales.
El consejo que se nos da es no usar variables globales
para evitar que funciones hagan mas de una cosa, diferente a como esta en su nombre

No hay botón ( descargar todos ) los archivos de la clase en este curso

Como cuando te piden corregir un bug, y esta escondido el efecto colateral.

Variables Globales 😳

No usar variables globales

Para usar variables en funciones, se las debe pasar como parametros.
No se puede utilizar variables globales a menos que sea estrictamente necesario.

No puedo usar variables globales ni siquiera en mis controladores para obtener la variable de configuración que mi proyecto carga de primeras?

POr facilidad, lo hacia global, ahora entiendo, debo poner más atención a como declarar por bloques

Bueno es mejor evitarlas lo más que se pueda

Jamás usar variables globales
  1. Evitar Efectos Colaterales
    Evitar usar variables globales
    No modificar datos que no se encuentren dentro del scope

No se nada de PHP

Esto puede resultar un poco confuso junto con el punto anterior, lo importante es no modificar valores dentro de secciones de código que no se supone que deberían modificar el valor.

Se reutilizan las variables después de reemplazar valores.
Faltan funciones para hacer el mismo proceso y evitar duplicar codigo.
Se llaman funciones que no se encuentran dentro de la clase.

RETO: los errores que pude encontrar con mi poco entendimiento de Php son: no utiliza escalamiento en las funciones del código, presenta código en bloque, no reutiliza código en una función donde era valido realizarlo

Muy buen ejemplo.

Momento favorito de la clase: 0:26

creo que hacen falta identificadores mnemotécnicos, específicos y precisos en los retos y ejemplos

Reto 4c: Hasta donde tengo entendido el único problema es que la clase Animal (de la que heredarán otras clases) no debería tener una función tan específica como volar, en cambio, la debería tener un animal que sí la necesite. O podría incorporarla con la condición de si tiene alas

`<?php
class Animal {
public function comer() {…}
public function reproducirse() {…}
public function fly()
{
if (! $this->hasWings) {
throw new Exception;
}
}
}

class Dog extends Animal
{
    // No sé muy bien cómo se ponen constructores en PHP pero ahí debería señalarse que NO TIENE ALAS!
}`

En uno de los retos habría que crear funciones en las tareas repetitivas, crear identificadores autodescriptivos, y hasta ahora por lo poco que entiendo de PHP y POO es que cada clase se podría modularizar en un archivo independiente con el nombre de la clase en sí, ademas de utilizar namespaces para evitar globalizar las variables

Todo muy claro. Gracias

En el reto 4e creo que la relación entre Manzano y ContadorDeManzanas debería ser jerarquica osea un ContadorDeManzanas extends Manzano .

Don comedia 0:24

Efecto colateral evidente!