Por qué cuesta cada vez mas dar servicios como programador a un proyecto Peruano


Como consejo para los emprendedores o empresas que contratan servicios de un programador, si este programador les termina el trabajo, pues, PAGUENLE. No puedes andar diciendole: "Mi cliente no me paga, esperame unos días y luego se hace 1 mes (2 meses, 3 meses, etc), y así hasta que el programador se ve forzado a quemar a su próximo ex-cliente por redes sociales o grupos de google.

Te ofrecen 5k por un mes de trabajo y te terminan pagando 2 ó 3 meses despues.

Lamentablemente, esto va a seguir, mientras haya chicos que por querer practicar o trabajar aceptan estas condiciones. Recordemos en primer lugar NO SOMOS SOCIOS de esta EMPRESA que ha contrato nuestro servicio.

Sugerencia

No cobren por proyecto. Ejemplo: Ya esto te cuesta 10k por 1 o 2 meses de trabajo. Terminaran pagando cuando quieren y siempre la última factura es la llave para que no "los abandones". Se han dado cuenta, que siempre esperan lo peor del programador, que firme contrato, que garantía me das, que quiero el código fuente, etc Pero, ellos nunca pierden y te pagan cuando quieren?

Entonces, Qué hacemos tio Joe?

Cobra por mes por recibos x honorarios, yo te cobro por mes tanto, tu me tienes que dar actividades ese mes como si fuera tu empleado.  Mi sueldo es 5k y hare lo que me pidas haga en ese rango. Terminado el mes me pagas. Claro esta, me firmas un documento por servicios profesionales y pago a recibos x honorarios; por actividades de programación; de manera que si no te paga vas al Ministerio de Trabajo.

Es hora que seamos mas formales, y no dejarnos llevar por las ganas de practicar, malogramos el mercado, malogramos las opciones de buenos programadores. Espero las Universidades, Institutos formen a sus chicos no sólo en tecnología, lenguajes de programación, frameworks, sino, también en como llevar su situación financiera, sus derechos laborales y como  hacer negocios en Perú. 

A cuantos les han robado sus proyectos, ideas, por no tener ni idea de lo que es propiedad intelectual, derechos de autor. 

Chicos informense bien. No mas "programadores combi". Si todos trabajamos formalmente, no habrá quienes se aprovechen de nuestra necesidad por trabajar. 

Ah! y terminen sus trabajos, también pongamosno del otro lado de la mesa. El emprendedor o empleado va a pagarte y no es justificable abandonar proyectos a medio camino, o hacer mál código. Recuerda todo se sabe, el mundo de la informática es chico. Hay una lista negra también. 

Nos leemos.

Enjoy!

Joe


Share:

Webinar para Gestión de Clientes


Si bien había escrito sobre la demo de Gestión de Clientes en 3 partes:


  1. Spring Boot + Thymeleaf + Bootstrap
  2. Agregando JasperReports a Gestión de Clientes
  3. Spring Security - Control de Permisos
Aproveche para este Domingo 24 de Mayo 2020 hacer un webinar para explicar todo en vivo. 
Así que si interesa tener detalles sobre el mismo, aquí te dejo el vídeo.






Todos los webinars y vídeos los puedes encontrar en nuestro canal de youtube.


Enjoy!

Joe



Share:

Spring Security - Control de Permisos de Url Dinámico



En un primer post mostramos como crear una aplicación con Spring Boot + Thymelaf + BooStrap + MySQL.  En un segundo post mostramos como generar reportes con JasperReports.

En este último post vamos a ver como agregar el proyecto Spring Security para manejar usuarios, roles, urls y permisos de forma dinámica a dichos urls sin necesidad de cambiar el código, todo trabajado desde la base de datos.

Código Fuente:  https://github.com/joedayz/gestionclientes


Configurando Spring Security

  • En el proyecto agregaremos la dependencia Starter de Spring Security. 



  • Empezaremos con la página de Login donde tendremos un formulario y enviaremos el username y password.


Configuración de Seguridad


Para que la seguridad funcione hay que crear un archivo de configuración Java denominado SecurityConfig.java en donde tendremos lo siguiente:


La clase es anotada con @EnableWebSecurity para permitir la integración entre Spring Security y Spring MVC. Este también hereda de WebSecurityConfigurerAdapter y te invita a sobreescribir un par de métodos para establecer configuración específica de seguridad web. 

@EnableGlobalMethodSecurity te permite habilitar seguridad glogal a nivel de métodos. 
  • El prePostEnable es una propiedad que permite anotaciones pre/post de seguridad.
  • proxyTargetClass es una propiedad  que indica que se usará proxies basados en CGLIB como alternativa a proxies basado en interfaces Java. La ventaja está explicada en este link.
  • @Import({CustomAuthorizationConfig.class}) permite tener configuración adicional en otro archivo y unirla con la configuración actual. 
  • @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER):  Para sobreescribir las reglas de acceso sin cambiar ninguna caracteristica auto configurada que viene por spring boot por defecto (más información en la documentación).

Mi CustomUserAuthenticationProvider


En Spring Security se pueden declarar varios Filtros para personalizar tu seguridad.



El primero filtro a implementar es el AuthenticationProvider y es una interface de Spring Security que nos permite implementar nuestra propia autenticación.


@Autowired
private AuthenticationProvider customUserAuthenticationProvider;

Entonces tengo que implementar dicha interface. A continuación la primera parte de la implementación:


Nos aseguramos que tenga la dependencias necesarias, cómo: Un UsuarioRepository para consultar la tabla Usuarios y una clase para consultar el Password acorde a la encriptación BCrypt que nos provee Spring.

Esta interface nos pide implementar 2 métodos:




En este método vemos si el usuario existe en la BD. Sino arrojamos una excepción UsernameNotFoundException. También validamos que el password corresponda y de no ser así arrojamos una excepción BadCredentialsException.







Esta clase que es invocada en dicho método se encarga de obtener los roles del usuario y devolverlos como una colección de GrantedAuthority

 Gracias a que vía JPA tenemos mapeado los usuario y roles podemos hacer eso sin problema.
El método final a implementar es este donde especificamos que la clase es de tipo UsernamePasswordAuthenticationToken. @Overridepublic boolean supports(Class authentication) { return UsernamePasswordAuthenticationToken.class.equals(authentication); } La tabla Usuario se verá de esta forma:

El AccessDecisionManager


Esta se encarga de la autorización. En mi caso no cambiare nada y tomare la autorización basada en roles.



Roles que tendrán la forma ROLE_XXX. Por eso guardaremos los Roles en esta tabla:





CustomWebSecurityExpressionHandler


Esta clase es para declarar que manejaremos la seguridad web basada en roles (getRoleHierarchy()) y permisos basado en expressiones (getPermissionEvaluator()).


@Componentpublic class CustomWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler {
   private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

   @Override   protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
      WebSecurityExpressionRoot root = new CustomWebSecurityExpressionRoot(authentication, fi);
      root.setPermissionEvaluator(getPermissionEvaluator());
      root.setTrustResolver(trustResolver);
      root.setRoleHierarchy(getRoleHierarchy());
      return root;
   }
}


FilterInvocationServiceSecurityMetadataSource

Implementar esta interface nos va a permitir que podamos tener de forma dinámica los URLs y los ROLES que pueden acceder a ellos.


Implementando InitializingBean nos permite al implementar afterPropertiesSet tener un método init() en nuestro bean.

Y como se puede apreciar en este método:


@Overridepublic void afterPropertiesSet() throws Exception {
   List<RequestConfigMapping> requestConfigMappings = requestConfigMappingService.getRequestConfigMappings();
   LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>(requestConfigMappings.size());
   for(RequestConfigMapping requestConfigMapping : requestConfigMappings) {
      RequestMatcher matcher = requestConfigMapping.getMatcher();
      requestMap.put(matcher,requestConfigMapping.getAttributes());
   }
   this.delegate = new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, expressionHandler);
}

El requestConfigMappingService nos da la relación entre URLs y permisos. Por lo tanto, implementamos JdbcRequestConfigMappingService implements RequestConfigMappingService



Y aquí el query que trae la relación:

private static final String SELECT_SQL = "select ant_pattern, expression from Filter_Metadata order by sort_order";



SecurityConfig

Implementando estas interfaces logramos que nuestra configuración sea minimalista y USUARIOS, ROLES, USUARIOS_ROLES, FILTERSECURITY_METADA (Urls y Roles) se manejen por base de datos.

Quedando nuestra clase de esta manera:




Ignoramos la seguridad para ciertos recursos y


Con esto terminamos nuestra demo de Clientes ( https://github.com/joedayz/gestionclientes) y ya puede manejar la seguridad con Spring Security.

Enjoy!


Joe


Share:

Agregando JasperReports a Gestión de Clientes


En un post anterior presente una integración con Spring Boot + Thymelaf + BooStrap + MySQL.

En esta nueva versión veremos la integración de JasperReports al proyecto Gestión de Clientes.

Código Fuente:  https://github.com/joedayz/gestionclientes

JasperReports

1. Al proyecto de Gestión de Clientes le hacía falta generar reportes.  Y para eso vamos a usar la librería gratuita de código abierto JasperReports

Agregaremos en el pom.xml:



NOTA: Nos aseguramos de tener la librereia itextpdf porque vamos a generar los reportes en PDF. 

Existe también un Editor de Reportes gratuito denominado JasperSoft Studio. Para el presente post yo voy a utilizar la versión JasperSoft Studio 6.8.0.





2. En el application.properties definiremos la ruta donde se ubicarán los reportes. Estos tienen extensión jrxml y compilado extensión jasper.  En el código fuente ver la carpeta Reportes



3. Para los reportes se ha reutilizado la búsqueda de clientes y agregado en el listado la opción de exportar o generar el reporte en PDF. 


En el Thymeleaf delegamos dicha tarea a un URL de la controladora:


4. En la controladora delegamos el trabajo de generar el reporte a RepositoryService.java


NOTA: 
- Se busca que al exportar el reporte se use el File Saver de manera que el usuario decida donde guardar su archivo.
- Verifique su navegador tenga habilitada dicha opción. 




5. ReporteService.java obtiene la data del cliente y delega al Repository el trabajo de generar el reporte.



6. El ReporteRepository.java busca los reportes compilados anteriormente con JasperSoft Studio y genera el reporte necesario.


Y eso es todo.

Vídeo del Resultado Final




Enjoy!!

Joe


Share:

Breves consejos para no tomar proyectos o como cerrarlos


Si vas a tomar un proyecto terminalo

La satisfacción del último commit y que el cliente quede contento es lo mejor que nos puede pasar. Nada de desaparecer o dejar el proyecto a medias. Lo que me ayuda y aconsejo con varios años ya en el mercado es evitar problemas desde el inicio y lo comparto con Ud. amigo lector: Debe existir un documento que describa la funcionalidad (llámele casos de usos o historias de usuario). Se los recomiendo porque si solo te da pantallas y no describes como va a funcionar, ambos terminaran como candidatos al programa de "Andrea" y pedirán "prueba de ADN" para ver quien dice la verdad. Pelea, tras pelea.
Con el documento, ya le dices, "eso no esta en el documento que acordamos. Si lo quieres es un cambio y costará X". Cuidado y la "necesidad" de tomar el proyecto te haga cerrar el trato de palabra. Esas se las lleva el viento. O peor abandonar a medio proyecto, no solo es que no trabajaras con este cliente más, sino que no tendrán confianza de ti para otro trabajo y el mundo de la informática es "pueblo chico". Hablara mál de ti y te hará la injusticia con otros clientes y ante la duda, pueden no elegirte los nuevos prospectos.

He tenido proyectos que han durado meses o años, por no hacer un documento de las funcionalidad y solo firmar la propuesta como listado de caracteristicas deseadas por aprovechar el negocio es un futuro fracaso para tí como independiente.
Déjame decirte que ahí estas frito (expresión peruana de que estas en serios problemas), ya que como no están las cosas claras, se reinventan funcionalidades todo el tiempo, se desgasta tu tiempo, tu cuerpo, tu presupuesto y nunca hay cuando acabar. El fin es hablar mal tu de él, o él de ti.

Si no te interesa, si no puedes hacerlo, dilo de inmediato

Y tambien si no puedes hacer algo por X motivos, mejor dilo de inicio. Sin dolor, no trates de quedar bien con el que te solicita tus servicios diciéndole que vas a ver, buscar alguien, etc. Dile de arranque no me interesa, no es el presupuesto que manejo, estoy ocupado, disculpame o la que no falla: "No se como hacerlo, sorry, yo hago otras cosas, no quiero quedar mal contigo".
Yo he perdido hasta amistades por que cuando me han pedido ayuda, no se las he podido atender y ojo, ni siquiera teníamos un proyecto, sino por demorarme en decirle, no puedo apoyarte, estoy en otros temas.
Es mas ni te comprometas a buscarle otra persona, hasta en eso te van a juzgar el desinterés. Hay que aprender a decir que NO.

Y para los que buscan buenos programadores

Hay de los que dicen que son "los magnificos" (de por sí, ¿que informatico no tiene ego?), que ha terminado nanodegress, que ha barrido con todos los cursos de coursera, que sabe GO, ELIXIR, CRISTAL, SWIFT, KOTLIN, etc. etc. Que pertenece a una comunidad hot y que recibe el apoyo de Marvel. Que es commiter de DC.
Sabes muchos de los que conozco que son muy buenos, son más de perfil bajo. Y la pregunta correcta que debes hacer es:

¿Terminas tus proyectos?, ¿me puedes dar los contactos de 3 ex clientes tuyos?
Es tu plata, tu tiempo y si lo vas a contratar, es mejor como en el futbol: Ir por quien ya tiene varios campeonatos y experiencia y no te deja como "novia frente al altar".

Nos leemos.
Joe











Share: