One place for hosting & domains

      SOLID: Los primeros 5 principios del diseño orientado a objetos


      Introducción

      SOLID es un acrónimo de los primeros cinco principios del diseño orientado a objetos (OOD) de Robert C. Martin (también conocido como el Tío Bob).

      Nota: Aunque estos principios pueden aplicarse a varios lenguajes de programación, el código de muestra que se incluye en este artículo usará PHP.

      Estos principios establecen prácticas que se prestan al desarrollo de software con consideraciones para su mantenimiento y expansión a medida que el proyecto se amplía. Adoptar estas prácticas también puede ayudar a evitar los aromas de código, refactorizar el código y aprender sobre el desarrollo ágil y adaptativo de software.

      SOLID representa:

      En este artículo, se le presentará cada principio por separado para comprender la forma en que SOLID puede ayudarlo a ser un mejor desarrollador.

      Principio de responsabilidad única

      El principio de responsabilidad única (SRP) establece:

      Una clase debe tener una y una sola razón para cambiar, lo que significa que una clase debe tener solo un trabajo.

      Por ejemplo, considere una aplicación que toma una colección de formas, entre círculos y cuadrados, y calcula la suma del área de todas las formas de la colección.

      Primero, cree las clases de forma y haga que los constructores configuren los parámetros requeridos.

      Para las cuadrados, deberá saber la longitud de un lado:

      class Square
      {
          public $length;
      
          public function construct($length)
          {
              $this->length = $length;
          }
      }
      

      Para los círculos, deberá saber el radio:

      class Circle
      {
          public $radius;
      
          public function construct($radius)
          {
              $this->radius = $radius;
          }
      }
      

      A continuación, cree la clase AreaCalculator y luego escriba la lógica para sumar las áreas de todas las formas proporcionadas. El área de un cuadrado se calcula por longitud al cuadrado. El área de un círculo se calcula mediante pi por el radio al cuadrado.

      class AreaCalculator
      {
          protected $shapes;
      
          public function __construct($shapes = [])
          {
              $this->shapes = $shapes;
          }
      
          public function sum()
          {
              foreach ($this->shapes as $shape) {
                  if (is_a($shape, 'Square')) {
                      $area[] = pow($shape->length, 2);
                  } elseif (is_a($shape, 'Circle')) {
                      $area[] = pi() * pow($shape->radius, 2);
                  }
              }
      
              return array_sum($area);
          }
      
          public function output()
          {
              return implode('', [
                '',
                    'Sum of the areas of provided shapes: ',
                    $this->sum(),
                '',
            ]);
          }
      }
      

      Para usar la clase AreaCalculator, deberá crear una instancia de la clase y pasar una matriz de formas para mostrar el resultado en la parte inferior de la página.

      A continuación, se muestra un ejemplo con una colección de tres formas:

      • un círculo con un radio de 2
      • un cuadrado con una longitud de 5
      • un segundo cuadrado con una longitud de 6
      $shapes = [
        new Circle(2),
        new Square(5),
        new Square(6),
      ];
      
      $areas = new AreaCalculator($shapes);
      
      echo $areas->output();
      

      El problema con el método de salida es que AreaCalculator maneja la lógica para generar los datos.

      Considere un escenario en el que el resultado debe convertirse a otro formato como JSON.

      La clase AreaCalculator manejaría toda la lógica. Esto violaría el principio de responsabilidad única. La clase AreaCalculator solo debe ocuparse de la suma de las áreas de las formas proporcionadas. No debería importar si el usuario desea JSON o HTML.

      Para abordar esto, puede crear una clase SumCalculatorOutputter por separado y usarla para manejar la lógica que necesita para mostrar los datos al usuario:

      class SumCalculatorOutputter
      {
          protected $calculator;
      
          public function __constructor(AreaCalculator $calculator)
          {
              $this->calculator = $calculator;
          }
      
          public function JSON()
          {
              $data = [
                'sum' => $this->calculator->sum(),
            ];
      
              return json_encode($data);
          }
      
          public function HTML()
          {
              return implode('', [
                '',
                    'Sum of the areas of provided shapes: ',
                    $this->calculator->sum(),
                '',
            ]);
          }
      }
      

      La clase SumCalculatorOutputter funcionaría así:

      $shapes = [
        new Circle(2),
        new Square(5),
        new Square(6),
      ];
      
      $areas = new AreaCalculator($shapes);
      $output = new SumCalculatorOutputter($areas);
      
      echo $output->JSON();
      echo $output->HTML();
      

      Ahora, la clase SumCalculatorOutputter maneja cualquier lógica que necesite para enviar los datos al usuario.

      Eso cumple con el principio de responsabilidad única.

      Principio abierto-cerrado

      Principio abierto-cerrado (S.R.P.) establece:

      Los objetos o entidades deben estar abiertos por extensión, pero cerrados por modificación.

      Esto significa que una clase debe ser ampliable sin modificar la clase en sí.

      Volvamos a ver la clase AreaCalculator y enfoquémonos en el método sum:

      class AreaCalculator
      {
          protected $shapes;
      
          public function __construct($shapes = [])
          {
              $this->shapes = $shapes;
          }
      
          public function sum()
          {
              foreach ($this->shapes as $shape) {
                  if (is_a($shape, 'Square')) {
                      $area[] = pow($shape->length, 2);
                  } elseif (is_a($shape, 'Circle')) {
                      $area[] = pi() * pow($shape->radius, 2);
                  }
              }
      
              return array_sum($area);
          }
      }
      

      Considere un escenario en el que el usuario desea la sum de formas adicionales como triángulos, pentágonos, hexágonos, etc. Tendría que editar constantemente este archivo y añadir más bloques if/else. Eso violaría el principio abierto-cerrado.

      Una forma de mejorar el método sum es eliminar la lógica para calcular el área de cada forma fuera del método de la clase AreaCalculator y adjuntarlo a la clase de cada forma.

      A continuación, se muestra area definido en Square:

      class Square
      {
          public $length;
      
          public function __construct($length)
          {
              $this->length = $length;
          }
      
          public function area()
          {
              return pow($this->length, 2);
          }
      }
      

      Y aquí es el método area definido en Circle:

      class Circle
      {
          public $radius;
      
          public function construct($radius)
          {
              $this->radius = $radius;
          }
      
          public function area()
          {
              return pi() * pow($shape->radius, 2);
          }
      }
      

      El método sum para AreaCalculator puede reescribirse así:

      class AreaCalculator
      {
          // ...
      
          public function sum()
          {
              foreach ($this->shapes as $shape) {
                  $area[] = $shape->area();
              }
      
              return array_sum($area);
          }
      }
      

      Ahora, puede crear otra clase de forma y pasarla al calcular la suma sin romper el código.

      Sin embargo, ahora surge otro problema: ¿Cómo sabe que el objeto pasado a AreaCalculator es realmente una forma o si la forma tiene un método llamado area?

      La codificación de una interface es una parte integral de SOLID.

      Cree un ShapeInterface que sea compatible con area:

      interface ShapeInterface
      {
          public function area();
      }
      

      Modifique sus clases de forma para implement el ShapeInterface.

      A continuación, se muestra la actualización a Square:

      class Square implements ShapeInterface
      {
          // ...
      }
      

      Y aquí está la actualización a Circle:

      class Circle implements ShapeInterface
      {
          // ...
      }
      

      En el método sum para AreaCalculator, puede verificar si las formas proporcionadas son realmente instancias de ShapeInterface; de lo contrario, lanzamos una excepción:

       class AreaCalculator
      {
          // ...
      
          public function sum()
          {
              foreach ($this->shapes as $shape) {
                  if (is_a($shape, 'ShapeInterface')) {
                      $area[] = $shape->area();
                      continue;
                  }
      
                  throw new AreaCalculatorInvalidShapeException();
              }
      
              return array_sum($area);
          }
      }
      

      Eso cumple con el principio abierto-cerrado.

      Principio de sustitución de Liskov

      El principio de sustitución de Liskov establece:

      Digamos que q(x) sea una propiedad demostrable sobre objetos de x, de tipo T. Entonces, q(y) debe ser demostrable para los objetos y, de tipo S, donde S es un subtipo de T.

      Esto significa que cada subclase o clase derivada debe ser sustituible por su clase base o clase principal.

      A partir de la clase AreaCalculator mostrada como ejemplo, considere una nueva clase VolumeCalculator que extiende la clase AreaCalculator:

      class VolumeCalculator extends AreaCalculator
      {
          public function construct($shapes = [])
          {
              parent::construct($shapes);
          }
      
          public function sum()
          {
              // logic to calculate the volumes and then return an array of output
              return [$summedData];
          }
      }
      

      Recuerde que la clase SumCalculatorOutputter se asemeja a esto:

      class SumCalculatorOutputter {
          protected $calculator;
      
          public function __constructor(AreaCalculator $calculator) {
              $this->calculator = $calculator;
          }
      
          public function JSON() {
              $data = array(
                  'sum' => $this->calculator->sum();
              );
      
              return json_encode($data);
          }
      
          public function HTML() {
              return implode('', array(
                  '',
                      'Sum of the areas of provided shapes: ',
                      $this->calculator->sum(),
                  ''
              ));
          }
      }
      

      Si intenta ejecutar un ejemplo como este:

      $areas = new AreaCalculator($shapes);
      $volumes = new VolumeCalculator($solidShapes);
      
      $output = new SumCalculatorOutputter($areas);
      $output2 = new SumCalculatorOutputter($volumes);
      

      Cuando invoca el método HTML en el objeto $output2, obtendrá un error E_NOTICE que le informará de conversión de matriz a cadena.

      Para solucionar esto, en vez de devolver una matriz desde el método sum de la clase VolumeCalculator, devuelva $summedData:

      class VolumeCalculator extends AreaCalculator
      {
          public function construct($shapes = [])
          {
              parent::construct($shapes);
          }
      
          public function sum()
          {
              // logic to calculate the volumes and then return a value of output
              return $summedData;
          }
      }
      

      $summedData puede ser float, double o integer.

      Eso cumple con el principio de sustitución de Liskov.

      Principio de segregación de interfaz

      El principio de segregación de interfaz establece:

      Un cliente nunca debe ser forzado a implementar una interfaz que no usan ni los clientes no deben ser forzados a depender de métodos que no usan.

      Siguiendo con el ejemplo anterior de ShapeInterface, tendrá que admitir las nuevas formas tridimensionales de Cuboid y Spheroid, y estas formas también tendrán que calcular el volumen.

      Consideraremos lo que sucedería si modificara ShapeInterface para añadir otro contrato:

      interface ShapeInterface
      {
          public function area();
      
          public function volume();
      }
      

      Ahora, cualquier forma que cree debe implementar el método volume, pero sabemos que las cuadrados son formas planas y que no tienen volumen, por lo que esta interfaz forzaría a la clase Square a implementar un método que no usa.

      Esto violaría el principio de segregación de interfaz. En su lugar, podría crear otra interfaz llamada ThreeDimensionalShapeInterface que tiene el contrato de volume y las formas tridimensionales pueden implementar esta interfaz:

      interface ShapeInterface
      {
          public function area();
      }
      
      interface ThreeDimensionalShapeInterface
      {
          public function volume();
      }
      
      class Cuboid implements ShapeInterface, ThreeDimensionalShapeInterface
      {
          public function area()
          {
              // calculate the surface area of the cuboid
          }
      
          public function volume()
          {
              // calculate the volume of the cuboid
          }
      }
      

      Este es un enfoque mucho mejor, pero hay que tener cuidado cuando se trata de escribir estas interfaces En vez de usar un ShapeInterface o un ThreeDimensionalShapeInterface, puede crear otra interfaz, quizá ManageShapeInterface e implementarla en las formas planas y en las tridimensionales.

      De esta manera, puede tener una sola API para administrar las formas:

      interface ManageShapeInterface
      {
          public function calculate();
      }
      
      class Square implements ShapeInterface, ManageShapeInterface
      {
          public function area()
          {
              // calculate the area of the square
          }
      
          public function calculate()
          {
              return $this->area();
          }
      }
      
      class Cuboid implements ShapeInterface, ThreeDimensionalShapeInterface, ManageShapeInterface
      {
          public function area()
          {
              // calculate the surface area of the cuboid
          }
      
          public function volume()
          {
              // calculate the volume of the cuboid
          }
      
          public function calculate()
          {
              return $this->area();
          }
      }
      

      Ahora en la clase AreaCalculator, puede sustituir la invocación al método area con calculate y también verificar si el objeto es una instancia de ManageShapeInterface y no de ShapeInterface.

      Eso cumple con el principio de segregación de interfaz.

      Principio de inversión de dependencia

      El principio de inversión de dependencia establece:

      Las entidades deben depender de abstracciones, no de concreciones. Indica que el módulo de alto nivel no debe depender del módulo de bajo nivel, sino que deben depender de las abstracciones.

      Este principio permite el desacoplamiento.

      A continuación, se muestra un ejemplo de un PasswordReminder que se conecta a una base de datos de MySQL:

      class MySQLConnection
      {
          public function connect()
          {
              // handle the database connection
              return 'Database connection';
          }
      }
      
      class PasswordReminder
      {
          private $dbConnection;
      
          public function __construct(MySQLConnection $dbConnection)
          {
              $this->dbConnection = $dbConnection;
          }
      }
      

      Primero, MySQLConnection es el módulo de bajo nivel mientras que PasswordReminder es de alto nivel, pero según la definición de D en SOLID, que establece que Depende de la abstracción y no de las concreciones. Este fragmento de código anterior viola este principio, ya que se está forzando a la clasevPasswordReminder a depender de la clase MySQLConnection.

      Si más adelante cambiara el motor de la base de datos, también tendría que editar la clase PasswordReminder, y esto violaría el principio abierto-cerrado.

      A la clase PasswordReminder no le debe importar qué base de datos usa su aplicación. Para solucionar estos problemas, se puede codificar a una interfaz, ya que los módulos de alto nivel y bajo nivel deben depender de la abstracción:

      interface DBConnectionInterface
      {
          public function connect();
      }
      

      La interfaz tiene un método connect y la clase MySQLConnection implementa esta interfaz. Además, en lugar de escribir directamente la clase MySQLConnection en el constructor del PasswordReminder, se indica la clase DBConnectionInterface y, sin importar el tipo de base de datos que utilice su aplicación, la clase PasswordReminder puede conectarse sin ningún problema a la base de datos y no se viola el principio abierto-cerrado.

      class MySQLConnection implements DBConnectionInterface
      {
          public function connect()
          {
              // handle the database connection
              return 'Database connection';
          }
      }
      
      class PasswordReminder
      {
          private $dbConnection;
      
          public function __construct(DBConnectionInterface $dbConnection)
          {
              $this->dbConnection = $dbConnection;
          }
      }
      

      Este código establece que los módulos de alto nivel y los de bajo nivel dependen de la abstracción.

      Conclusión

      En este artículo, se le presentaron los cinco principios del código SOLID. Los proyectos que se adhieren a los principios SOLID pueden compartirse con los colaboradores, ampliarse, modificarse, probarse y refactorizarse con menos complicaciones.

      Continúe aprendiendo leyendo sobre otras prácticas para el desarrollo ágil y adaptativo de software.



      Source link

      Cómo habilitar la renderización del lado del servidor para una aplicación React


      Introducción

      La renderización del lado del servidor (SSR) es una técnica popular para renderizar una aplicación de una sola página (SPA) del lado del cliente en el servidor y enviar una página completamente renderizada al cliente. Esto permite que los componentes dinámicos se presenten como marcado HTML estático.

      Este enfoque puede ser útil para la optimización del motor de búsqueda (SEO) cuando la indexación no gestiona el JavaScript correctamente. También puede ser beneficioso en situaciones en las que descargar un paquete JavaScript grande sea difícil debido a una red lenta.

      En este tutorial, iniciará una aplicación React usando Create React App y luego modificará el proyecto para habilitar la renderización del lado del servidor.

      Al final de este tutorial, tendrá un proyecto funcional con una aplicación React del lado del cliente y una aplicación Express del lado del servidor.

      Nota: Alternativamente, Next.js ofrece un enfoque moderno para crear aplicaciones renderizadas estáticas y en servidor creadas con React.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      Este tutorial se verificó con Node v14.4.0 y npm v6.14.5.

      Paso 1: Crear la aplicación React y modificar el componente de la aplicación

      Primero, usamos npx para iniciar una nueva aplicación React usando la última versión de Create React App.

      Vamos a invocar nuestra aplicación my-ssr-app:

      A continuación, hacemos cd al nuevo directorio:

      cd my-ssr-app
      

      Finalmente, iniciamos nuestra nueva aplicación del lado del cliente para verificar la instalación:

      Debería ver una aplicación React de ejemplo en la ventana de su navegador.

      Ahora, vamos a crear un componente <Home>:

      A continuación, añada el siguiente código al archivo Home.js:

      src/Home.js

      import React from 'react';
      
      export default props => {
        return <h1>Hello {props.name}!</h1>;
      };
      

      Esto creará un encabezado <h1> con un mensaje "Hello" dirigido a un nombre.

      A continuación, vamos a renderizar <Home> en el componente <App>. Abra el archivo App.js:

      Luego, sustituya las líneas de código existentes con estas nuevas líneas de código:

      src/App.js

      import React from 'react';
      import Home from './Home';
      
      export default () => {
        return <Home name="Sammy" />;
      };
      

      Esto pasa un nombre al componente <Home> de forma que el mensaje que esperamos mostrar sea "Hello Sammy!".

      En el archivo index.js de nuestra aplicación, usaremos el método hydrate de ReactDOM en vez de render para indicar al renderizador DOM que estamos rehidratando la aplicación tras una renderización del lado del servidor.

      Vamos a abrir el archivo index.js:

      A continuación, sustituya el contenido del archivo index.js con el siguiente código:

      index.js

      import React from 'react';
      import ReactDOM from 'react-dom';
      import App from './App';
      
      ReactDOM.hydrate(<App />, document.getElementById('root'));
      

      Con esto concluye la configuración del lado del cliente y podemos pasar a configurar el lado del servidor.

      Paso 2: Crear un servidor Express y renderizar el componente de la aplicación

      Ahora que tenemos nuestra aplicación lista, vamos a configurar un servidor que enviará una versión renderizada. Usaremos Express para nuestro servidor. Vamos a añadirlo al proyecto introduciendo el siguiente comando en la ventana de su terminal:

      • npm install express@4.17.1

      O usando yarn:

      A continuación, cree un directorio server junto al directorio src de la aplicación:

      A continuación, cree un nuevo archivo index.js que contendrá el código del servidor Express:

      Añada las importaciones que necesitará y defina algunas constantes:

      server/index.js

      import path from 'path';
      import fs from 'fs';
      
      import React from 'react';
      import express from 'express';
      import ReactDOMServer from 'react-dom/server';
      
      import App from '../src/App';
      
      const PORT = process.env.PORT || 3006;
      const app = express();
      

      A continuación, añada el código del servidor con algunas funciones para la gestión de errores:

      server/index.js

      // ...
      
      app.get('/', (req, res) => {
        const app = ReactDOMServer.renderToString(<App />);
      
        const indexFile = path.resolve('./build/index.html');
        fs.readFile(indexFile, 'utf8', (err, data) => {
          if (err) {
            console.error('Something went wrong:', err);
            return res.status(500).send('Oops, better luck next time!');
          }
      
          return res.send(
            data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
          );
        });
      });
      
      app.use(express.static('./build'));
      
      app.listen(PORT, () => {
        console.log(`Server is listening on port ${PORT}`);
      });
      

      Como puede ver, podemos importar nuestro componente <App> desde la aplicación del cliente directamente desde el servidor.

      Aquí suceden tres cosas importantes:

      • Indicaremos a Express que sirva contenido desde el directorio build como archivos estáticos.
      • Usamos un método desde ReactDOMServer, renderToString para renderizar nuestra aplicación a una secuencia HTML estática.
      • A continuación, leemos el archivo estático index.html desde la aplicación creada del cliente, inyectamos el contenido estático de nuestra aplicación en el <div> con un id de "root" y enviamos eso como la respuesta a la solicitud.

      Paso 3: Configurar webpack, Babel y secuencias de comandos npm

      Para que funcione el código de nuestro servidor, necesitaremos empaquetarlo y compilarlo usando webpack y Babel. Para conseguir esto, vamos a añadir las dependencias dev al proyecto introduciendo el siguiente comando en la ventana de su terminal:

      • npm install webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --save-dev

      O usando yarn:

      • yarn add webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --dev

      Nota: Una versión anterior de este tutorial instaló babel-core, babel-preset-env, y babel-preset-react-app. Estos paquetes han sido archivados desde entonces, y se utilizan las versiones repo mono.

      A continuación, cree un archivo de configuración Babel:

      A continuación, añada los valores prestablecidos env y react-app:

      .babelrc.json

      {
        "presets": [
          "@babel/preset-env",
          "@babel/preset-react"
        ]
      }
      

      Nota: Una versión anterior de este tutorial usó un archivo .babelrc (no una extensión de archivo .json). Este era un archivo de configuración para Babel 6, pero ya no es así para Babel 7.

      Ahora, crearemos una configuración webpack para el servidor que utiliza Babel Loader para compilar el código. Comience creando el archivo:

      Luego, añada las siguientes configuraciones al archivo webpack.server.js:

      webpack.server.js

      const path = require('path');
      const nodeExternals = require('webpack-node-externals');
      
      module.exports = {
        entry: './server/index.js',
      
        target: 'node',
      
        externals: [nodeExternals()],
      
        output: {
          path: path.resolve('server-build'),
          filename: 'index.js'
        },
      
        module: {
          rules: [
            {
              test: /.js$/,
              use: 'babel-loader'
            }
          ]
        }
      };
      

      Con esta configuración, nuestro paquete compilado de servidor aparecerá a la carpeta server-build en un archivo llamado index.js.

      Observe que el uso target: 'node' y externals: [nodeExternals()] desde webpack-node-externals, que solo omitirá los archivos desde node_modules en el paquete; el servidor puede acceder a estos archivos directamente.

      Esto completa la instalación de la dependencia y la configuración de webpack y Babel.

      Ahora repasaremos package.json para ayudar secuencias de comandos npm de ayuda:

      Añadiremos secuencias de comandos dev:build-server, dev:start y dev al archivo package.json para crear y presentar nuestra aplicación SSR fácilmente:

      package.json

      "scripts": {
        "dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
        "dev:start": "nodemon ./server-build/index.js",
        "dev": "npm-run-all --parallel build dev:*",
        ...
      },
      

      Usamos nodemon para reiniciar el servidor cuando realicemos cambios. Y usamos npm-run-all para ejecutar varios comandos en paralelo.

      Vamos a instalar esos paquetes ahora introduciendo los siguientes comandos en la ventana de su terminal:

      • npm install nodemon@2.0.4 npm-run-all@4.1.5 --save-dev

      O usando yarn:

      • yarn add nodemon@2.0.4 npm-run-all@4.1.5 --dev

      Con esto, puede ejecutar lo siguiente para crear la aplicación del lado del cliente, empaquetar y compilar el código del servidor e iniciar el servidor en :3006:

      O usando yarn:

      La configuración webpack de nuestro servidor vigilará los cambios y nuestro servidor se reiniciará cuando haya cambios. Para la aplicación cliente, sin embargo, actualmente aún debemos crearla cada vez que realicemos cambios. Hay un problema abierto para eso aquí.

      Ahora, abra http://localhost:3006/ en su navegador web y verá su aplicación renderizada en el lado del servidor.

      Previamente, el código fuente reveló:

      Output

      <div id="root"></div>

      Pero ahora, con los cambios que ha realizado, el código fuente revela:

      Output

      <div id="root"><h1 data-reactroot="">Hello <!-- -->Sammy<!-- -->!</h1></div>

      La renderización del lado del servidor convirtió el componente <App> a HTML.

      Conclusión

      En este tutorial, inició una aplicación React y habilitó la renderización del lado del servidor.

      Con esta publicación, solo hemos visto un poco de lo que es posible. Las cosas se complican un poco cuando el direccionamiento, la recuperación de datos o Redux también tengan que ser parte de una aplicación renderizada en el lado del servidor.

      Un beneficio importante de usar SR es tener una aplicación que pueda rastrearse para ver su contenido, incluso para rastreadores que no ejecutan código JavaScript. Esto puede ayudar con la optimización de los motores de búsqueda (SEO) y la transmisión de metadatos a los canales de redes sociales.

      SSR también puede ayudar a menudo con el rendimiento porque una aplicación completamente cargada se envía desde el servidor sobre la primera solicitud. Para aplicaciones no triviales, su valor puede variar porque SSR requiere una configuración que puede volverse algo complicada y crea una mayor carga sobre el servidor. Si utiliza la renderización del lado del servidor para su aplicación React depende de sus necesidades específicas y de qué ventajas tienen más sentido para su caso de uso.

      Si desea aprender más sobre React, eche un vistazo a nuestra serie Cómo crear código en React.js, o consulte nuestra página del tema React para ver ejercicios y proyectos de programación.



      Source link

      Cómo monitorizar el estado del servidor con Checkmk en Ubuntu 18.04


      El autor seleccionó a Open Internet/Free Speech Fund para recibir una donación como parte del programa Write for DOnations.

      Introducción

      Cómo administrador del sistema, es una buena práctica conocer el estado actual de su infraestructura y servicios. Idealmente, querrá darse cuenta de los discos que fallan o los tiempos de inactividad de la aplicación antes de que lo hagan sus usuarios. Las herramientas de monitorización como Checkmk pueden ayudar a los administradores a detectar estos problemas y a mantener los servidores en perfecto estado.

      Generalmente, el software de monitorización puede realizar un seguimiento del hardware de sus servidores, el tiempo de actividad y los estados de servicio, y puede presentar alertas si algo va mal. En un escenario muy básico, un sistema de monitorización le alertaría si algún servicio falla. En uno más robusto, las notificaciones llegarían poco después de que surja cualquier señal sospechosa, como un mayor uso de la memoria o una cantidad anormal de conexiones TCP.

      Existen muchas soluciones de monitorización disponibles que ofrecen varios grados de complejidad y conjuntos de funciones, tanto gratuitas como comerciales. En muchos casos, la instalación, configuración y gestión de estas herramientas es difícil y requieren mucho tiempo.

      Checkmk, sin embargo, es una solución de monitorización robusta y sencilla de instalar. Es un paquete de software autónomo que combina Nagios (un servicio de alertas popular y de código abierto) con complementos para recopilar, monitorizar y realizar gráficos de los datos. También cuenta con la interfaz web de Checkmk, una herramienta integral que aborda muchas de las deficiencias de Nagio. Ofrece un panel de control fácil de usar, un sistema de notificaciones completo y un repositorio de agentes de monitorización fáciles de instalar para muchas distribuciones Linux. Si no fuese por la interfaz web de Checkmk, tendríamos que utilizar diferentes vistas para diferentes tareas y no sería posible configurar todas esas funciones sin recurrir a amplias modificaciones de archivos.

      En esta guía, configuraremos Checkmk en un servidor Ubuntu 18.04 y monitorizaremos dos hosts independientes. Monitorizaremos el servidor Ubuntu también como servidor CentOS 7 independiente, pero podríamos usar el mismo enfoque para añadir cualquier cantidad de hosts adicionales a nuestra configuración de monitorización.

      Requisitos previos

      Paso 1: Instalar Checkmk en Ubuntu

      Para usar nuestro sitio de monitorización, primero debemos instalar Checkmk en el servidor Ubuntu. Esto nos proporcionará las herramientas que necesitamos. Checkmk ofrece archivos de paquete Ubuntu listos para usar que podemos utilizar para instalar nuestro paquete de software.

      Primero, vamos a utilizar la lista de paquetes para tener la versión más reciente de los listados del repositorio:

      Para examinar los paquetes, podemos ir al sitio de listado de paquetes. En el menú de la página puede seleccionarse Ubuntu 18.04 entre otros.

      Ahora, descargue el paquete:

      • wget https://checkmk.com/support/1.6.0p8/check-mk-raw-1.6.0p8_0.bionic_amd64.deb

      A continuación, instale el paquete recién descargado:

      • sudo apt install -y ./check-mk-raw-1.6.0p8_0.bionic_amd64.deb

      Este comando instalará el paquete Checkmk junto con todas las dependencias necesarias, incluyendo el servidor web Apache que se usa para proporcionar acceso web a la interfaz de monitorización.

      Tras completarse la instalación, ahora podemos acceder al comando omd. Pruébelo:

      Este comando omd generará el siguiente resultado:

      Output

      Usage (called as root): omd help Show general help . . . General Options: -V <version> set specific version, useful in combination with update/create omd COMMAND -h, --help show available options of COMMAND

      El comando omd puede gestionar todas las instancias Checkmk en nuestro servidor. Puede iniciar y detener todos los servicios de monitorización a la vez, y podremos utilizarlo para crear nuestra instancia Checkmk. Primero, sin embargo, tenemos que actualizar los ajustes de nuestro firewall para permitir el acceso externo a los puertos web predeterminados.

      Paso 2: Configurar el firewall

      Antes de poder trabajar con Checkmk, es necesario permitir el acceso externo al servidor web en la configuración del firewall. Asumiendo que siguió los pasos de configuración del firewall en los requisitos previos, tendrá un firewall UFW configurado para restringir el acceso a su servidor.

      Durante la instalación, Apache se registra con UFW para proporcionar una forma sencilla de habilitar o deshabilitar el acceso a Apache a través del firewall.

      Para permitir el acceso a Apache, utilice el siguiente comando:

      Ahora, verifique los cambios:

      Verá que Apache está listado entre los servicios permitidos:

      Output

      Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Apache ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Apache (v6) ALLOW Anywhere (v6)

      Esto nos permitirá acceder a la interfaz web de Checkmk.

      En el siguiente paso, crearemos la primera instancia de monitorización de Checkmk.

      Paso 3: Crear una instancia de monitorización de Checkmk

      Checkmk utiliza el concepto de instancias, o instalaciones individuales, para aislar múltiples copias de Checkmk en un servidor. En la mayoría de los casos, una única copia de Checkmk es suficiente y así es como configuraremos el software en esta guía.

      Primero, debemos proporcionar un nombre a nuestra nueva instancia, y usaremos monitoring en este texto Para crear la instancia, escriba:

      • sudo omd create monitoring

      La herramienta omd configurará todo automáticamente. El comando debe tener un aspecto similar al siguiente:

      Output

      Adding /opt/omd/sites/monitoring/tmp to /etc/fstab. Creating temporary filesystem /omd/sites/monitoring/tmp...OK Restarting Apache...OK Created new site monitoring with version 1.6.0p8.cre. The site can be started with omd start monitoring. The default web UI is available at http://your_ubuntu_server/monitoring/ The admin user for the web applications is cmkadmin with password: your-default-password (It can be changed with 'htpasswd -m ~/etc/htpasswd cmkadmin' as site user.) Please do a su - monitoring for administration of this site.

      En este resultado, se resaltarán la dirección URL, nombre predeterminado del usuario y contraseña para acceder a nuestra interfaz de monitorización. La instancia se crea ahora, pero aún debe iniciarse. Para iniciar la instancia, escriba:

      • sudo omd start monitoring

      Ahora, todas las herramientas y servicios necesarios se iniciarán a la vez. Al final, veremos un resultado que verifica que todos nuestros servicios se han iniciado correctamente:

      Output

      Starting mkeventd...OK Starting rrdcached...OK Starting npcd...OK Starting nagios...OK Starting apache...OK Initializing Crontab...OK

      La instancia está lista.

      Para acceder a la instancia Checkmk, abra http://your_ubuntu_server_ip/monitoring/ en el navegador web. Se le solicitará una contraseña. Utilice las credenciales predeterminadas impresas previamente en la pantalla; cambiaremos estos valores predeterminados más adelante.

      La pantalla de Checkmk se abre con un panel de control, que muestra todos nuestros servicios y los estados del servidor en listas, y utiliza gráficos prácticos que se parecen a la Tierra. Justo después de la instalación, estos están vacíos, pero pronto se mostrarán estados para nuestros servicios y sistemas.

      Panel de control en blanco de Checkmk

      En el siguiente paso, cambiaremos la contraseña predeterminada para proteger el sitio usando esta interfaz.

      Paso 4: Cambiar su contraseña administrativa

      Durante la instalación, Checkmk genera una contraseña aleatoria para el usuario administrativo cmkadmin. Esta contraseña debe cambiarse tras la instalación, y como tal, a menudo es corta y no muy segura. Podemos cambiar esto a través de la interfaz web.

      Primero, abra la página Users desde el menú WATO – Configuration a la izquierda. La lista mostrará todos los usuarios que actualmente tiene acceso al sitio de Checkmk. En una nueva instalación, listará solo dos usuarios. El primero, automation, está destinado a ser usado con herramientas automatizadas; el segundo es el usuario cmkadmin, que usamos para iniciar sesión en el sitio.

      Lista de usuarios Checkmk

      Haga clic en el icono de lápiz junto al usuario cmkadmin para cambiar sus detalles, incluyendo la contraseña.

      Formulario de edición para el usuario admin de Checkmk

      Actualice la contraseña, añada un correo electrónico de administrador y realice cualquier otro cambio que quiera.

      Tras guardar los cambios, nos solicitará que iniciemos sesión de nuevo con nuestras nuevas credenciales. Haga esto y vuelva al panel de control, donde hay una cosa más que debemos hacer para aplicar por completo nuestra nueva configuración.

      De nuevo, abra la página Users desde el menú WATO – Configuration a la izquierda. El botón naranja en la esquina superior derecha etiquetado como 1 Change nos indica que hemos realizado algunos cambios a la configuración de Checkmk, y que debemos guardarlos y activarlos. Esto sucederá cada vez que cambiemos la configuración de nuestro sistema de monitorización, no solo tras editar las credenciales del usuario. Para guardar y activar los cambios pendientes, debemos hacer clic en este botón y aceptar activar los cambios enumerados usando la opción Activate affected en la siguiente pantalla.

      Lista de usuarios de Checkmk tras las modificaciones Activar la pantalla de configuración en los cambios de configuración Cambios de configuración activados correctamente

      Tras activar los cambios los datos del nuevo usuario se escriben en los archivos de configuración serán usados por todos los componentes del sistema. Checkmk notifica automáticamente a los componentes individuales del sistema de monitorización, recargándolos cuando sea necesario y administrando todos los archivos de configuración necesarios.

      La instalación de Chekmk ahora está lista para usarse. En el siguiente paso, añadiremos el primer host a nuestro sistema de monitorización.

      Paso 5: Monitorizar el primer host

      Ahora estamos listos para monitorizar el primer host. Para conseguir esto, primero instalaremos check-mk-agent en el servidor Ubuntu. A continuación, restringiremos el acceso a los datos de monitorización usando xinetd.

      Los componentes instalados con Checkmk se encargan de recibir, almacenar y presentar la información de monitorización. No proporcionan información en sí mismos.

      Para recopilar datos reales, usaremos el agente de Checkmk. Diseñado específicamente para este trabajo, el agente de Checkmk es capaz de monitorizar todos los componentes vitales del sistema a la vez y de reportar esa información a la instancia de Checkmk.

      Instalar el agente

      El primer host que monitorizaremos será your_ubuntu_server, el servidor sobre el cual hemos instalado la instancia Checkmk.

      Para comenzar, debemos instalar el agente de Checkmk. Los paquetes para todas las distribuciones principales, incluyendo Ubuntu, están disponibles directamente desde la interfaz web. Abra la página Monitoring Agents desde el menú WATO – Configuration a la izquierda. Verá las descargas de agente disponibles con los paquetes más populares bajo la primera sección, etiquetada como Packaged agents.

      Lista de agentes de monitorización empaquetados disponibles

      El paquete check-mk-agent_1.6.0p8-18_all.ded es el adecuado para las distribuciones basadas en Debian, incluyendo Ubuntu. Copie el enlace de descarga para ese paquete desde el navegador web y utilice esa dirección para descargar el paquete.

      • wget http://your_ubuntu_server_ip/monitoring/check_mk/agents/check-mk-agent_1.6.0p8-1_all.deb

      Tras su descarga, instale el paquete:

      • apt install -y ./check-mk-agent_1.6.0p8-1_all.deb

      Ahora, verifique que el agente se ha instalado correctamente:

      El comando generará un texto muy largo que parece un texto sin sentido, pero combina toda la información vital sobre el sistema en un solo lugar.

      Output

      <<<check_mk>>> Version: 1.6.0p8 AgentOS: linux . . . ["monitoring"] <<<job>>> <<<local>>>

      Checkmk utiliza el resultado de este comando para recopilar datos de esto desde los hosts monitorizados. Ahora, restringiremos el acceso a los datos de monitorización usando xinetd.

      Restringir el acceso a los datos de monitorización utilizando xinetd

      Por defecto, los datos de check_mk_agent se presentan usando xinetd, un mecanismo que genera datos sobre un cierto puerto de red tras acceder a él. Esto significa que podemos acceder a chek_mk_agent usando telnet al puerto 6556 (el puerto predeterminado para Checkmk) desde cualquier otro equipo en Internet a menos que la configuración de nuestro firewall no lo permita.

      No es una buena política de seguridad publicar información vital sobre los servidores a nadie en Internet. Solo deberíamos permitir a los hosts que ejecuten Checkmk y estén bajo supervisión acceder a estos datos, de forma que solo nuestro sistema de monitorización pueda recopilarlos.

      Si siguió el tutorial de configuración inicial del servidor, incluyendo los pasos sobre cómo configurar un firewall, el acceso al agente Checkmk está bloqueado por defecto. Sin embargo, es una buena práctica aplicar estas restricciones de acceso directamente en la configuración del servicio, y no depender únicamente de un firewall para su protección.

      Para restringir el acceso a los datos del agente, tenemos que editar el archivo de configuración en /etc/xinetd.d/check_mk. Abra el archivo de configuración en su editor favorito. Para utilizar nano, escriba:

      • sudo nano /etc/xinetd.d/check_mk

      Localice esta sección:

      /etc/xinetd.d/check_mk

      . . .
      # configure the IP address(es) of your Nagios server here:
      #only_from      = 127.0.0.1 10.0.20.1 10.0.20.2
      . . .
      

      El ajuste only_from se encarga de restringir el acceso a ciertas direcciones IP. Debido a que ahora estamos trabajando en monitorizar el mismo servidor sobre el que Checkmk se está ejecutando, está bien permitir que localhost se conecte. Elimine y actualice el ajuste de configuración a:

      /etc/xinetd.d/check_mk

      . . .
      # configure the IP address(es) of your Nagios server here:
      only_from      = 127.0.0.1
      . . .
      

      Guarde el archivo y ciérrelo.

      El daemon xinetd debe reiniciarse para que los cambios surtan efecto. Hágalo ahora:

      • sudo systemctl restart xinetd

      Ahora, nuestro agente está en funcionamiento y restringido para aceptar solo las conexiones locales. Podemos proceder a configurar la monitorización para ese host usando Checkmk.

      Configurar el host en la interfaz web de Checkmk

      Primero, para añadir un nuevo host a monitorizar tenemos que ir al menú Hosts en el menú WATO – Configuration a la izquierda. Desde aquí, haga clic en Create new host. Se nos solicitará cierta información sobre el host.

      Creación de un nuevo host en Checkmk

      El Hostname es el nombre familiar que Checkmk usará para la monitorización. Puede ser un nombre de dominio completamente cualificado, pero no es necesario. En este ejemplo, llamaremos al host monitoring, igual que el nombre de la instancia Checkmk. Debido a que monitoring no se resuelve a nuestra dirección IP, también debemos proporcionar la dirección IP de nuestro servidor. Y ya que estamos monitorizando el host local, la IP será simplemente 127.0.0.1. Seleccione la casilla IPv4 Address para habilitar la entrada manual de la IP e introduzca el valor en el campo de texto.

      La configuración predeterminada de la sección Data Sources depende del agente Checkmk para proporcionar los datos de monitorización, lo que está bien. El ajuste Networking Segment se usa para indicar los hosts en las redes remotas, que se caracterizan por una mayor latencia esperada, lo cual no es una señal de mal funcionamiento. Ya que este es un host local, el ajuste predeterminado también está bien.

      Para guardar el host y configurar qué servicios se monitorizarán, haga clic en el botón Save & go to services.

      Lista de servicios disponibles para monitorizar

      Checkmk realizará un inventario automático. Eso significa que recopilará el resultado del agente y lo descifrará para saber qué tipos de servicios puede monitorizar. Todos los servicios disponibles para la monitorización estarán en la lista, incluyendo carga de CPU, uso de memoria y espacio libre en los discos.

      Para habilitar la monitorización de todos los servicios descubiertos, debemos hacer clic en el botón Monitor bajo la sección Undecided services (currently not monitored). Esto actualizará la página, pero ahora todos los servicios se listarán bajo la sección Monitored services, informándonos de que están siendo monitorizados.

      Igual que cuando cambiamos nuestra contraseña de usuario, estos nuevos cambios deben guardarse y activarse antes de que estén activos. Pulse el botón 2 changes y acepte lo cambios usando el botón Activate affected. Tras esto, la monitorización del host estará lista.

      Ahora está listo para trabajar con los datos de su servidor. Eche un vistazo al panel de control principal utilizando el elemento de menú Overview/Main Overview (Información/Información principal) a la izquierda.

      Trabajar con los datos de la monitorización

      Ahora, vamos a ver el panel de control principal usando el menú Overview/Main Overview a la izquierda:

      Panel de control de la monitorización con todos los servicios en buen estado

      La esfera de la Tierra está completamente verde y la tabla dice que un host está activo sin problemas. Podemos ver la lista completa de hosts, que ahora consta de un único host, en la vista Hosts/All hosts (usando el menú de la izquierda).

      Lista de los hosts con todos los servicios en buen estado

      Ahí veremos cuántos servicios están en buen estado (en verde), cuántos están fallando y cuántos deben comprobarse aún. Tras hacer clic en el nombre del host, podremos ver la lista de todos los servicios con sus estados completos y sus Perf-O-Meters. El Perf-O-Meter muestra el rendimiento de un único servicio en relación con lo que Checkmk considera que es un buen estado.

      Detalles del estado de un servicio de host

      Todos los servicios que devuelven datos que pueden ponerse en un gráfico mostrarán un icono de gráfico junto a su nombre. Podemos utilizar ese ícono para obtener acceso a los gráficos asociados con el servicio. Ya que la monitorización del host es nueva, los gráficos no tienen casi nada, pero, tras algún tiempo, los gráficos proporcionarán información valiosa sobre cómo cambia el rendimiento de nuestro servicio a lo largo del tiempo.

      Gráficos que representan la carga en la CPU del servidor

      Cuando cualquiera de estos servicios falle o se recupere, la información se mostrará en el panel de control. Para los servicios que fallan, se mostrará un error en rojo, y el problema también estará visible en el gráfico de la Tierra.

      Panel de control con un host con problemas

      Tras la recuperación, todo se mostrarán en verde, lo que indica un buen funcionamiento, pero el registro de eventos de la derecha contendrá información sobre fallos anteriores.

      Panel de control con un host recuperado tras presentar problemas

      Ahora que hemos explorado el panel de control, vamos a añadir un segundo host a nuestra instancia de monitorización.

      Paso 6: Monitorizar un segundo host CentOS

      La monitorización es realmente útil cuando tiene varios hosts. Ahora añadiremos un segundo servidor a nuestra instancia Checkmk, esta vez ejecutando CentOS 7.

      Al igual que con nuestro servidor Ubuntu, es necesario instalar el agente Checkmk para recopilar datos de monitorización en CentOS. Esta vez, sin embargo, necesitaremos un paquete rpm desde la página Monitoring Agentes en la interfaz web, llamado check-mk-agent-1.6.0p8-1.noarch.rpm.

      Primero, sin embargo, debemos instalar xinetd, que por defecto no está disponible en la instalación CentOS. Xinetd, como recordará, es un daemon responsable de poner a disposición sobre la red los datos de monitorización proporcionados por check_mk_agent.

      En su servidor CentOS, primero instale xinetd:

      • sudo yum install -y xinetd

      Ahora podemos descargar e instalar el paquete del agente de monitorización necesario para nuestro servidor CentOS:

      • sudo yum install -y http://your_ubuntu_server_ip/monitoring/check_mk/agents/check-mk-agent-1.6.0p8-1.noarch.rpm

      Igual que antes, podemos verificar que el agente funciona correctamente ejecutando check_mk_agent:

      El resultado será similar al del servidor Ubuntu. Ahora, restringiremos el acceso al agente.

      Restringir el acceso

      Esta vez no monitorizaremos un host local, de forma que xinetd debe permitir las conexiones que provienen del servidor Ubuntu, donde Checkmk está instalado, para recopilar los datos. Para permitir esto, primero abra su archivo de configuración:

      • sudo vi /etc/xinetd.d/check_mk

      Aquí verá la configuración para su servicio check_mk, especificando cómo se puede acceder al agente Checkmk a través del daemon xinetd. Busque las siguientes dos líneas comentadas:

      /etc/xinetd.d/check_mk

      . . .
      # configure the IP address(es) of your Nagios server here:
      #only_from      = 127.0.0.1 10.0.20.1 10.0.20.2
      . . .
      

      Ahora, elimine la segunda línea y sustituya las direcciones IP locales con your_ubuntu_server_ip:

      /etc/xinetd.d/check_mk

      . . .
      # configure the IP address(es) of your Nagios server here:
      only_from      = your_ubuntu_server_ip
      . . .
      

      Guarde y salga del archivo escribiendo :x y luego ENTER. Reinicie el servicio xinetd usando:

      • sudo systemctl restart xinetd

      Ahora podemos configurar Checkmk para que monitorice nuestro host CentOS 7.

      Configurar un nuevo host en Checkmk

      Para añadir hosts adicionales a Checkmk, usamos el menú Hosts como hicimos antes. Esta vez, llamaremos al host centos, configuraremos su dirección IP, y seleccionaremos WAN (high-latency) bajo la casilla de selección Networking Segment, ya que el host está en otra red. Si omitimos esto y lo dejamos como local, Checkmk pronto nos alertará de que el host está desconectado, ya que esperaría que respondiese a las consultas del agente mucho más rápido de lo que es posible por Internet.

      Crear la pantalla de configuración del segundo host

      Haga clic en Save & go to services, lo que mostrará los servicios disponibles para monitorizar sobre el servidor CentOS. La lista será muy similar a la del primer host. De nuevo, esta vez debemos hacer clic en Monitor y, luego, activar los cambios utilizando el botón naranja en la esquina superior izquierda.

      Tras activar los cambios, podemos verificar que el host está siendo monitorizado en la página All hosts. Vaya allí. Ahora estarán visibles dos hosts, monitoring y centos.

      Lista de hosts con dos hosts monitorizados

      Ahora está monitorizando un servidor Ubuntu y un servidor CentOS con Checkmk. Es posible monitorizar aún más hosts. De hecho, no hay un límite aparte del rendimiento del servidor, que no debería ser un problema hasta que su número de hosts sea de cientos. Además, el procedimiento es el mismo para cualquier otro host. Los agentes Checkmk en los paquetes deb y rpm funcionan en Ubuntu, CentOS y en la mayoría de las otras distribuciones Linux.

      Conclusión

      En esta guía hemos configurado dos servidores con dos distribuciones Linux diferentes: Ubuntu y CentOS. A continuación, instalamos y configuramos Checkmk para monitorizar ambos servidores, y exploramos la potente interfaz web de Checkmk.

      Checkmk permite configurar fácilmente un sistema de monitorización completo y versátil, que empaqueta todo el difícil trabajo de la configuración manual en una interfaz web fácil de usar con múltiples opciones y funciones. Con estas herramientas es posible monitorizar múltiples hosts; configurar correo electrónico, SMS o notificaciones push cuando se produzcan problemas; configurar comprobaciones adicionales para más servicios; monitorizar la accesibilidad y el rendimiento, etcétera.

      Para obtener más información sobre Checkmk, asegúrese de visitar la documentación oficial.



      Source link