Aleksandrs Bickovs, Author at ProdSens.live https://prodsens.live/author/aleksandrs-bickovs/ News for Project Managers - PMI Tue, 11 Jun 2024 19:20:30 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 https://prodsens.live/wp-content/uploads/2022/09/prod.png Aleksandrs Bickovs, Author at ProdSens.live https://prodsens.live/author/aleksandrs-bickovs/ 32 32 Confluence Gantt Chart: How-to Guide With Pros, Cons & Alternatives https://prodsens.live/2024/06/11/confluence-gantt-chart-how-to-guide-with-pros-cons-alternatives/?utm_source=rss&utm_medium=rss&utm_campaign=confluence-gantt-chart-how-to-guide-with-pros-cons-alternatives https://prodsens.live/2024/06/11/confluence-gantt-chart-how-to-guide-with-pros-cons-alternatives/#respond Tue, 11 Jun 2024 19:20:30 +0000 https://prodsens.live/2024/06/11/confluence-gantt-chart-how-to-guide-with-pros-cons-alternatives/ confluence-gantt-chart:-how-to-guide-with-pros,-cons-&-alternatives

There are many software solutions to make a Gantt chart, from simple data visualization tools to specialized Gantt…

The post Confluence Gantt Chart: How-to Guide With Pros, Cons & Alternatives appeared first on ProdSens.live.

]]>
confluence-gantt-chart:-how-to-guide-with-pros,-cons-&-alternatives

There are many software solutions to make a Gantt chart, from simple data visualization tools to specialized Gantt chart software equipped with advanced project planning, scheduling and tracking tools.

Each of these alternatives has unique pros and cons depending on the industry, business size and the level of functionality expected from a Gantt chart tool, which is why it’s important to understand Gantt chart software to know which Gantt chart features are the most useful for the project and its team.

In this blog, we’ll go over the main pros and cons of making a Confluence Gantt chart, as well as some alternatives that can be used. We recently reviewed the best Gantt chart software alternatives and highlighted their key features, pricing and other important details to consider when choosing a tool for a project team.

What Is Confluence?

Confluence is a team collaboration and productivity tool that allows remote team members to work together online. For example, users can make, store and manage documents online in real time, establish a communication channel for sharing announcements and documents at the enterprise and team levels and brainstorm using whiteboards, posts, data visualization tools and messaging features.

Does Confluence Have a Gantt Chart?

No, Confluence doesn’t have a built-in Gantt chart feature. It has a timeline tool that looks like a Gantt chart at first glance because it uses a bar chart to map tasks on a timeline. However, on closer inspection it’s clear it’s not a Gantt chart. First, it lacks a table, spreadsheet or grid to show project task details like every Gantt chart does. On top of that, it lacks basic Gantt chart functions, such as visualizing task progress, identifying critical path activities or mapping task dependencies.

ProjectManager, an award-winning project and portfolio management software, has a robust Gantt chart tool for managing projects that makes interactive project schedules, balances team member’s workload, tracks task progress and costs, links four types of task dependencies and identifies the critical path of your projects. These and other features make ProjectManager’s Gantt chart an ideal solution for managing projects across industries. Get started with ProjectManager for free today.

ProjectManager has real Gantt charts that help plan, manage and track projects in real time. Learn more

How to Create a Gantt Chart in Confluence

While Confluence doesn’t have a Gantt chart, there are two alternative solutions or workarounds to make a Gantt chart using Confluence. One is embedding a Gantt chart from Jira. The second is getting a Gantt chart app from the Confluence app marketplace.

Method 1: Jira, a project management tool that’s also made by Atlassian, makes it easy to use with Confluence. Jira has two tools that can make a Gantt chart: timelines and plans.

Import the Jira Gantt chart into Confluence to share it with team members. The main advantage of this method is that Jira timelines can be embedded in a Confluence workspace.

Method 2: There are various free and paid Confluence marketplace apps and integrations to make a basic Gantt chart. Each has its pros and cons, but generally, the main advantage of these apps is that they’re simple to use and are specifically designed for making Gantt charts, unlike Confluence or Jira.

However, none of these methods will make a fully-fledged Gantt chart, which leaves many users looking for an alternative for making a Confluence Gantt chart. Find out why by making a Gantt chart in ProjectManager. Better understand what a real Gantt chart can do when seamlessly integrated with essential project management tools.

How to Make a Gantt Chart With ProjectManager

ProjectManager’s Gantt chart offers advanced project management features, but it’s still an easy-to-use tool thanks to its intuitive user interface. It’s an ideal solution for both beginning and experienced project management software users. That’s because it’s a versatile tool for managing projects: planning, scheduling and tracking tasks, workflows or business processes, all in real time.

Get started by taking ProjectManager’s 30-day free trial. Then follow these steps to make a Gantt chart.

1. Make a New Project

Click the New icon and then select Project. A window will pop up.

 

 

Select whether to make a Gantt chart from scratch by listing project tasks and entering their details manually or by importing an Excel, CSV or Microsoft Project file to use its data to populate the Gantt chart.

 

 

2. Choose the Gantt Chart View and Enter Project Data

Select the Gantt chart by clicking the icon shown in the image below. On the left side, there’s a grid or spreadsheet with columns to enter details about project tasks, such as task names, estimated duration, due dates, assignee, costs and much more.

 

 

The information entered in these columns will automatically populate the visual timeline on the right side. This Gantt chart timeline will show such details as who’s responsible for each task, its percentage of completion, project milestones and task dependencies. In addition, it will highlight the critical path for the project schedule.

3. Assign Tasks to Team Members and Collaborate Online

Once the project tasks have been mapped on the Gantt chart, they can be assigned to team members. In addition, ProjectManager has timesheets, workload management charts and other time management features to help track the work hours of each team member, their labor costs and current availability.

 

 

ProjectManager has unlimited file storage to hold all project documentation, which can be shared with the project team. To further collaboration, kanban boards can share messages and files in real time at the task level. Teams are always up to date on changes and updates with email notifications and in-app alerts.

4. Track Project Progress, Schedule, Resources & Costs

Real-time dashboards automatically collect live data from the Gantt chart and display project metrics, such as time, cost, workload and more, in easy-to-read graphs and charts for a high-level overview of progress. Customizable reports get more detailed information on project and portfolio status, workload, timesheets, variance and more.

Resource management tools, such as the color-coded workload chart and team page show resource allocation and can balance workload to keep teams working at capacity and increase productivity.

 

Top 3 Confluence Gantt Chart Integrations, Key Features, Prices and Ratings

While not as robust as ProjectManager, there are Confluence Gant chart integrations. Here’s a quick overview of the top three Confluence Gantt chart integrations and their current price and ratings in the Confluence apps marketplace.

1. Smartsheet for Confluence

This integration allows users to access some of Smartsheet’s project management tools in the Confluence workspace, such as Gantt charts, worksheets, dashboards and calendars.

Price: $12 per month
Free Trial: 30-day free trial
Rating/User Reviews: 4/4

2. Table Filter, Charts & Spreadsheets for Confluence by Stiltsoft Europe OÜ

This app offers basic data visualization tools that turn Confluence tables into Gantt charts. By listing tasks, their start and finish dates, this Confluence Gantt chart integration will automatically make a Gantt chart based on that information.

Price: $27 per month
Free Trial: 30-day free trial
Rating/User Reviews: 3.9/4

3. Mermaid Charts & Diagrams for Confluence by weweave UG

Mermaid Charts & Diagrams makes various diagrams, including Gantt charts, to visualize the data from the Confluence pages.

Price: $9.20 per month
Free Trial: 30-day free trial
Rating/User Reviews: 3.7/4

Free Gantt Chart Template for Excel

This free Gantt chart template for Excel is a great alternative to the Confluence Gantt chart apps described above. It automatically generates a Gantt chart for projects based on a list of tasks, their due dates and estimated duration. Simply fill out the columns and then customize the Gantt chart as needed.

Gantt Chart template for Microsoft Excel

However, for the best Gantt chart experience for project managers and their teams, use ProjectManager.

Why ProjectManager Is the Best Confluence Gantt Chart Alternative

We’ve already mentioned some advantages of using ProjectManager’s Gantt chart. However, ProjectManager offers many other project management tools and features besides Gantt charts. Here are some main reasons that make ProjectManager the best Confluence Gantt chart alternative.

Multiple Project Management Tools

Gantt charts are only one of multiple project views, all updated simultaneously so everyone is always working on the most current project data. There is the visual workflow of kanban boards, project calendars, task lists and a sheet view, which is like a Gantt chart without the timeline. Managers, teams and stakeholders can choose the tool that best serves their needs. For example, kanban boards give a more detailed view of each of the tasks in the Gantt chart. Users can edit task details and collaborate with the team as well. Any changes made in any of the project tools are reflected across all views.

Online Team Collaboration Features

Like Confluence, ProjectManager has team collaboration features; There’s document management with unlimited file storage, which allows team members to access files anywhere and at any time. There are also built-in messaging and file sharing features, email notifications to stay updated on changes and the project team can tag one another. Team management features include dashboards, workload charts and the team page to monitor the activity of all team members and track their progress, workload and labor costs on secure timesheets.

Advanced Gantt Chart Software Features

ProjectManager Gantt charts give users advanced features that most Gantt chart tools lack, such as identifying the critical path, linking all four types of task dependencies to avoid costly delays, work breakdown structure hierarchy levels, comparing cost estimates vs. actual project costs and more.

Disadvantages of Creating a Confluence Gantt Chart Using Jira

As we’ve hinted at, the main disadvantage of using Jira to make a Gantt chart that can be shared in a Confluence workspace is that it simply doesn’t have a Gantt chart tool. Instead, it has a task list and a timeline view, which can be used to make the two main elements of a Gantt chart, a table or grid with project tasks and a stacked bar chart that works as a project timeline.

Additionally, these tools have some Gantt chart features such as basic task dependency mapping and progress tracking. However, these tools are designed to make a product roadmap for software development teams, so they’re not the best alternative for those looking for a Gantt chart tool for task or project management.

On top of these drawbacks, having access to Jira’s timeline and plans requires a monthly fee of $12.50 per user.

Disadvantages of Creating a Gantt Chart Using Confluence Marketplace Apps

While Confluence is a great tool for managing project documents and streamlining your team communication, it’s not a Gantt chart software. To make things worse, its integrations are very limited in terms of project management functionality.

Unfortunately, most Confluence Gantt chart integrations only visualize data in a Gantt chart format. They lack advanced features such as resource allocation, cost tracking, schedule baselining, critical path management and many more.

Most of these apps aren’t free. That means paying for multiple Confluence integrations to get the same functionality that a single Gantt chart software like ProjectManager can provide.

But these methods can’t compete with the project management functionality provided by software equipped with fully featured Gantt charts, such as ProjectManager. On top of that, ProjectManager integrates with Jira, which allows data to flow between ProjectManager, Jira and Confluence.

We’ve reviewed the best Gantt chart software alternatives to help understand what are the key features to consider when choosing a tool for the project team. Here are some of them.

ProjectManager is online project and portfolio management software that connects teams in the office, out in the field and anywhere in between. They can share files, comment at the task level and stay updated with email and in-app notifications. Join teams at Avis, Nestle and Siemens who use our tool to deliver successful projects. Get started with ProjectManager today for free.

The post Confluence Gantt Chart: How-to Guide With Pros, Cons & Alternatives appeared first on ProjectManager.

The post Confluence Gantt Chart: How-to Guide With Pros, Cons & Alternatives appeared first on ProdSens.live.

]]>
https://prodsens.live/2024/06/11/confluence-gantt-chart-how-to-guide-with-pros-cons-alternatives/feed/ 0
4 Proven Strategies to Succeed in a Technical Interview https://prodsens.live/2024/02/24/4-proven-strategies-to-succeed-in-a-technical-interview/?utm_source=rss&utm_medium=rss&utm_campaign=4-proven-strategies-to-succeed-in-a-technical-interview https://prodsens.live/2024/02/24/4-proven-strategies-to-succeed-in-a-technical-interview/#respond Sat, 24 Feb 2024 15:20:43 +0000 https://prodsens.live/2024/02/24/4-proven-strategies-to-succeed-in-a-technical-interview/ 4-proven-strategies-to-succeed-in-a-technical-interview

4 Proven Strategies to Succeed in a Technical Interview – howtouselinux discuss 4 proven strategies that will help…

The post 4 Proven Strategies to Succeed in a Technical Interview appeared first on ProdSens.live.

]]>
4-proven-strategies-to-succeed-in-a-technical-interview


4 Proven Strategies to Succeed in a Technical Interview – howtouselinux

discuss 4 proven strategies that will help you succeed in a technical interview.

favicon
howtouselinux.com

The post 4 Proven Strategies to Succeed in a Technical Interview appeared first on ProdSens.live.

]]>
https://prodsens.live/2024/02/24/4-proven-strategies-to-succeed-in-a-technical-interview/feed/ 0
Day 5 – The 12 Days of DEV: May 2023 https://prodsens.live/2023/12/24/day-5-the-12-days-of-dev-may-2023/?utm_source=rss&utm_medium=rss&utm_campaign=day-5-the-12-days-of-dev-may-2023 https://prodsens.live/2023/12/24/day-5-the-12-days-of-dev-may-2023/#respond Sun, 24 Dec 2023 09:24:23 +0000 https://prodsens.live/2023/12/24/day-5-the-12-days-of-dev-may-2023/ day-5-–-the-12-days-of-dev:-may-2023

Greetings on Day 5 of “The 12 Days of DEV”! 🎄🎉 As we approach the year’s end, let’s…

The post Day 5 – The 12 Days of DEV: May 2023 appeared first on ProdSens.live.

]]>
day-5-–-the-12-days-of-dev:-may-2023

Greetings on Day 5 of “The 12 Days of DEV”! 🎄🎉 As we approach the year’s end, let’s journey through the top two articles of May 2023.

This compilation showcases the community’s favorites, determined by a mix of comments, reactions, and page views (with just a very subtle touch of editorial curation). And while these articles shine as the most popular, it’s worth noting that they vary from the DEV team’s chosen Weekly Top 7 (though there might be some shared gems.) 🌟

Explore the mechanics of storing “likes” on platforms like Instagram and Facebook. From unraveling data types to crafting efficient data models using ScyllaDB, @danielhe4rt navigates the complexities with an engaging narrative, making Database 101 an accessible journey for beginners in the realm of database architecture.

Take a cloud journey with @kelvinskell, exploring the intricacies of deploying a three-tier architecture on AWS. From VPC creation to CloudFront distribution, this guide navigates through presentation, logic, and data layers, integrating Terraform for automation. Delve into the layers of CloudFront, Elastic Load Balancer, and more, concluding with insights into future DevOps and reporting layers.

Stay tuned for the next installment of “The 12 Days of DEV” as we continue to unwrap the community’s favorite articles. Happy reading, and we look forward to sharing more highlights with you! 📚🎁

The post Day 5 – The 12 Days of DEV: May 2023 appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/12/24/day-5-the-12-days-of-dev-may-2023/feed/ 0
What Defines a Software Developer? Navigating Beyond Technical Expertise https://prodsens.live/2023/11/04/what-defines-a-software-developer-navigating-beyond-technical-expertise/?utm_source=rss&utm_medium=rss&utm_campaign=what-defines-a-software-developer-navigating-beyond-technical-expertise https://prodsens.live/2023/11/04/what-defines-a-software-developer-navigating-beyond-technical-expertise/#respond Sat, 04 Nov 2023 23:25:00 +0000 https://prodsens.live/2023/11/04/what-defines-a-software-developer-navigating-beyond-technical-expertise/ what-defines-a-software-developer?-navigating-beyond-technical-expertise

Defining any profession is a complex task, and the domain of software development is no exception. It requires…

The post What Defines a Software Developer? Navigating Beyond Technical Expertise appeared first on ProdSens.live.

]]>
what-defines-a-software-developer?-navigating-beyond-technical-expertise

Defining any profession is a complex task, and the domain of software development is no exception. It requires not only a technical sense but also a deep understanding of the complexity of the software industry. In this article, we dive deep into the multiple aspects of a software developer as a person, exploring the qualities that go beyond technical skills.

This exploration is based on my two-year journey in the field. While I share my observations, it’s important to note that the software development landscape is vast and constantly evolving. Thus, this perspective is open to discussion, correction, and even disagreement, as the beauty of this profession lies in its various approaches and interpretations.

Image description

Beyond Technical Skills

Evolving as a developer is a transformative journey that encompasses more than just mastering programming languages and frameworks. It’s a unique set of qualities and skills that define a software developer’s superiority.

Here are some key aspects I’ve observed during my experience:

1. Curiosity

Curiosity is a fundamental trait that as humans we possess, but for a software developer, it takes on an entirely different dimension. It’s not just about being curious; it’s about diving deep into the details of your work. For instance, when you’re engrossed in a project, curiosity should drive you to question every aspect of it.
Image description
Begin by questioning the purpose of a feature: Why do we need it? What impact will it have on the other features? Question the tools you’re using: Why this particular tool? Or why opt for a ‘for’ loop instead of ‘forEach’? Can this complex piece of code be simplified without compromising functionality? Understanding the reasons behind every decision, and every line of code.

Maintaining this level of curiosity isn’t easy; it demands relentless questioning and a genuine hunger for understanding. Yet, it is this hunger that fuels your growth as a developer and promotes the developer to explore, experiment, and innovate, pushing the boundaries of your knowledge and expertise. Embracing this unquenchable curiosity transforms a good developer into an exceptional one.

2. Effective Communication

Albert Einstein’s timeless wisdom, “If you can’t explain it simply, you don’t understand it well enough” resonates profoundly with software development. Developers need to communicate complex technical concepts in a clear, understandable manner. Whether collaborating with team members, explaining ideas to clients, or documenting projects, communication skills are essential.

Consider this scenario: your client might lack the technical know-how of the product, while your junior colleague might be well-versed in technical complexities but lacks a broader understanding of its functionality. Bridging this gap demands a subtle approach to communication. It’s about simplifying complex jargon into understandable terms, ensuring that both the client and your team comprehensively grasp the information being conveyed.

One of my seniors once remarked that he sometimes feels like he doesn’t work in an IT company but in a call center. This observation reflects the communication-heavy nature of our work. Most of our tasks involve discussions over calls, whether it’s trying to understand a feature or explaining the same concept to others. Despite the challenges, effective communication remains the backbone of our collaborative efforts.
Image description

3. Teamwork and Collaboration

Software development rarely happens in isolation. Developers work within teams, collaborating with diverse professionals such as designers, testers, and project managers. The ability to collaborate effectively, respect differing opinions, and contribute positively to a team dynamic is crucial for project success.
Image description
Effective collaboration extends beyond mere coexistence or routine morning status calls. It manifests in the willingness to support one another, promoting an environment where team members assist with understanding features, solving complex lines of code, or seamlessly stepping in when a colleague needs assistance. This collaborative spirit isn’t merely about shared tasks; it’s about building a collective knowledge base, elevating each other’s skills, and strengthening the team’s cohesion.

4. Continuous Learning and Humility

In the tech world, learning is vital because things are always changing fast. Even though it can be frustrating how often new technologies come up (as humorously shown on dayssincelastjavascriptframework), it’s a reality for developers. This means developers must continuously learn to keep up with market trends.

It’s important to stay humble and recognize that there’s always room to learn, even for experienced professionals. Valuable insights can come from both newcomers and junior developers.
Image description
Implementing a culture of continuous learning might seem straightforward in smaller or flat organizational structures. However, in larger multinational corporations, it can sometimes be overlooked but these corporations are trying hard to create an open and transparent environment that encourages learning.

So, always be open to learning new things and stay humble. It’s not just about surviving; it’s about thriving in the ever-changing tech world.

Conclusion

Image description
I am not sure about the purpose of the article, but I believe that along with technical proficiency, software developers must develop other important qualities as well. These qualities can help to transform a good developer into an exceptional one. As the software development industry continues to evolve, the traits that define a truly outstanding software developer may also change. In my opinion, these several qualities can contribute to a developer’s excellence.

The post What Defines a Software Developer? Navigating Beyond Technical Expertise appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/11/04/what-defines-a-software-developer-navigating-beyond-technical-expertise/feed/ 0
Explorando os Conceitos Básicos do Kotlin: Parte I https://prodsens.live/2023/10/29/explorando-os-conceitos-basicos-do-kotlin-parte-i/?utm_source=rss&utm_medium=rss&utm_campaign=explorando-os-conceitos-basicos-do-kotlin-parte-i https://prodsens.live/2023/10/29/explorando-os-conceitos-basicos-do-kotlin-parte-i/#respond Sun, 29 Oct 2023 02:24:52 +0000 https://prodsens.live/2023/10/29/explorando-os-conceitos-basicos-do-kotlin-parte-i/ explorando-os-conceitos-basicos-do-kotlin:-parte-i

💟 Eai, como cês tão? Essa é a primeira parte de um conteúdo que será dividido em duas…

The post Explorando os Conceitos Básicos do Kotlin: Parte I appeared first on ProdSens.live.

]]>
explorando-os-conceitos-basicos-do-kotlin:-parte-i

💟 Eai, como cês tão?

Essa é a primeira parte de um conteúdo que será dividido em duas partes, onde exploraremos a documentação do Kotlin.

Antes de criar este conteúdo, pesquisei como poderia contribuir com a tradução da documentação oficial, mas em resumo, eles incentivam traduções, porém a hospedagem e publicação da tradução são de responsabilidade do tradutor, e ela não será incorporada ao site oficial da linguagem Kotlin. Mais informações, aqui

Ressalto a importância de também consultar a documentação oficial, uma vez que essa fonte é regularmente atualizada e abriga uma vasta quantidade de informações detalhadas. Além disso, a documentação do Kotlin é maravilhosa.

A proposta dessa primeira parte é falar sobre os fundamentos do Kotlin, abordando a parte inicial e básica.

Bônus: Ao final, compartilharei alguns recursos da IDE IntelliJ que podem ajudar ainda mais na sua aprendizagem sobre a linguagem. 🤯

Ana, sobre o que vamos falar? Nesta primeira parte, vou abordar:

  • Por que Kotlin?
  • Variáveis
  • Tipos Básicos
  • Coleções
  • Fluxo de Controle
  • Funções
  • Bônus

Por que Kotlin?

Image description

Kotlin é uma linguagem de programação de código aberto desenvolvida pela JetBrains.

  • É projetada para ser compatível com o Java e é popular para o desenvolvimento de aplicativos Android.
  • É concisa, segura, legível e expressiva.
  • Resolve limitações do Java e é executada na JVM.
  • Destaca-se por sua segurança em relação a referências nulas.
  • Permite a interoperabilidade com o Java e é compatível com bibliotecas existentes.
  • Ampla adoção na comunidade de desenvolvimento, especialmente para aplicativos Android.

Meu primeiro “Hello, World” em Kotlin

💀 Olha só, para evitar possíveis “maldições” – já que há uma lenda que afirma que começar o aprendizado sem um simples “Hello, World!” pode dificultar a compreensão dos princípios básicos – vamos iniciar com um “Hello World” em Kotlin. Não que eu acredite, mas vai que né

E para isso, podemos utilizar o “playground” do Kotlin, que permite que você crie e execute códigos por lá. Legal, né?

fun main() {
    println("Hello, World!")
}
  • Em Kotlin a palavra-chave fun é usada para declarar uma função.
  • A função main() é onde o seu programa começa.
  • O corpo de uma função é escrito entre chaves {}.
  • As funções println() e print() imprimem seus argumentos na saída padrão.

Me lembrou um pouco Python ou eu to doida?! 😅

Variáveis

🔹 Todo programa precisa ser capaz de armazenar dados, e as variáveis nos ajudam a fazer isso. Em Kotlin, você pode declarar:

  • Variáveis que não podem ser mudadas, utilizando val.
  • Variáveis mutáveis, ou seja, que podem ser alteradas, utilizando var.
  • Para atribuir um valor, usamos o operador de atribuição =.
val age = 25 //imutável

var age = 25//mutável

As variáveis podem ser declaradas no início do seu programa, fora da função main(), por exemplo. Quando você as declara dessa forma, elas são consideradas variáveis globais.

E aqui segue a recomendação de sempre declararmos variáveis utilizando val. Utilizar var somente se necessário.

Template string

🔹 Sabe aqueles momentos em que precisamos adicionar uma ou mais variáveis em uma string? Então, é ai que as templates de strings podem ser bem úteis.

Vale lembrar que em Kotlin, um valor de string é uma sequência de caracteres entre aspas duplas “. Por exemplo:

val name = "Ana Laura Reis"

As templates strings sempre começam com um $. Exemplo:

val age = 25

val name = "Ana Laura Reis"

val template = "My name is $name and I am $age years old"

Nesse exemplo, $name será substituído pelo valor da variável name e $age pelo valor da variável age.

Se quiser saber mais sobre template string, dê uma olhada aqui.

Tipos básicos

🔹 Os tipos são importantes para entendermos o que estamos armazenando em uma variável ou até mesmo quais funções e propriedades aquele dado possui.

Nos exemplos acima já foi possível vermos dois tipos, int e string. A variável name é do tipo string e age do tipo int.

O Kotlin possui a habilidade de deduzir o tipo de dados de uma variável e isso é chamado de inferência de tipo.

Quando você atribui um valor inteiro à variável age, o Kotlin infere que age possui um tipo de dado numérico, especificamente do tipo Int.

Tá Ana, e o que isso significa na prática? Isso significa que o compilador “sabe” que você pode realizar operações aritméticas, como adição, subtração, multiplicação ou divisão, com a variável age.

Essa inferência de tipo é uma das características poderosas do Kotlin, pois permite que você escreva código de forma concisa e legível, sem precisar especificar explicitamente o tipo de dados a todo momento.

No geral, Kotlin possui os seguintes tipos básicos:

Tipo Descrição Exemplo
Int Números inteiros 42
Long Números inteiros longos 1234567890L
Float Números de ponto flutuante de precisão simples 3.14f
Double Números de ponto flutuante de dupla precisão 3.14
Char Caractere 'a'
String Sequência de caracteres "Olá, mundo!"
Boolean Valor lógico (verdadeiro ou falso) true ou false

Para saber mais sobre tipos básicos consulte a documentação.

E se eu quiser iniciar uma variável sem necessariamente atribuir um valor? 🤔

// variável declarada sem inicialização/sem valor atribuído
val age : Int

// variável inicializada/atribuindo o valor 25 à variável age
val age = 25

// declarando tipo e atribuindo valor
val name : String = "Ana"

Acho que o exemplo conseguiu explicar bem!

🧠 Agora faça os exercícios para praticar o que aprendemos até aqui

Coleções

🔹 Lembra das listas, arrays? Os famosos tipos de dados que utilizamos para agrupar uma quantidade n de dados.

Em Kotlin temos algumas estruturas de dados para agrupar itens:

Coleção Descrição
List Coleção ordenada de elementos, pode conter duplicatas. Permite acesso por índices.
Set Coleção não ordenada de elementos únicos.
Map Coleção de pares chave-valor, onde cada chave é única.
ArrayList Implementação modificável de uma lista usando um array.
LinkedList Implementação modificável de uma lista usando uma estrutura de lista encadeada.
HashSet Implementação de um conjunto usando uma tabela de dispersão para armazenar elementos únicos.
TreeSet Implementação de um conjunto usando uma estrutura de árvore balanceada para armazenar elementos únicos, mantendo a ordem.
HashMap Implementação de um mapa usando uma tabela de dispersão para armazenar pares chave-valor, com chaves únicas.
TreeMap Implementação de um mapa usando uma estrutura de árvore balanceada para armazenar pares chave-valor, mantendo a ordem.

Falaremos mais detalhadamente sobre:

  1. List
  2. Set
  3. Map

Para saber mais sobre os outros tipo, consulte a documentação oficial (ou comenta aqui, quem sabe crio um conteúdo sobre isso)

1. List

Podemos ter:

  • Uma coleção ordenada de elementos.
  • Permite elementos duplicados.
  • Os elementos podem ser acessados por índices.

🔹 Para criar uma lista que não pode ser modificada (List), você utiliza a função listOf() e se quiser criar uma lista que pode ser modificada (MutableList), você utiliza a função mutableListOf().

Caso queira dizer o tipo dos elementos da sua lista, você pode fazer isso usando <>, vou mostrar alguns exemplos abaixo:

// Lista imutável
val listImmutable = listOf("Ana", "Gabriel", "Maria")

//Lista mutável e tipada

val listMutable:  MutableList<String> = mutableListOf("Ana", "Gabriel", "Maria")

Podemos acessar qualquer elemento da lista através de seu índice:

val favoriteMusics = lisOf("Rap", "Funk", "Pagode")

favoriteMusics[0] // acessando o item "Rap" da minha lista

Podemos acessar o primeiro e o último elemento de uma lista utilizando as funções:

  • .first()
  • .last()

Os dois exemplos acima são funções de extensão. Em resumo, os métodos são ações diretamente ligadas a uma classe, enquanto as funções de extensão são novas ações que você pode adicionar a uma classe existente sem modificar a classe original. Eles permitem estender a funcionalidade da classe de uma forma mais flexível.

Para entender melhor sobre essas funções dê uma olhada aqui.

Outra coisa legal que conseguimos pra fazer é verificar se existe um item em uma lista utilizando in.

println("Rap" in favoriteMusics)

Também podemos adicionar e remover itens de uma lista, utilizando o .add() e .remove()

// Adiciona "Samba" no final da lista

favoriteMusics.add("Samba")

// Remove "Rap" da lista

favoriteMusics.remove("Rap")

2. Set

  • Uma coleção que não mantém uma ordem específica.
  • Como os conjuntos não são ordenados, você não consegue acessar um item através do seu índice.
  • Contém apenas elementos únicos, não permitindo duplicatas.

Assim como nas listas também podemos criar um set mutável ou imutável:

// Imutável 

val fruits = setOf("banana", "morango", "pêra")

//Mutável

val newFruits: MutableSet<String> = mutableSetOf("banana", "morango", "pêra", "maçã")

Ah algo interessante é que o set contêm apenas elementos únicos, todo item duplicado é descartado. 👀

Também conseguimos usar as funções add e remove para adicionarmos e removermos algum item do nosso set, caso ele seja mutável.

3. Map

  • Uma coleção de pares chave-valor, onde cada chave é única.
  • As chaves são usadas para acessar os valores associados.
  • Não mantém uma ordem específica para os pares chave-valor.

🔹 Podemos imaginar um map como um menu de comida. Você pode encontrar o preço (valor), encontrando a comida (chave) que deseja comer. Os mapas são úteis se você quiser procurar um valor sem usar um índice numerado, como em uma lista.

// Imutável 
val menu = mapOf("coxinha" to 2, "coquinha" to 3, "batata" to 10)

// Isso aqui nos retorna: {coxinha=2, coquinha=3, batata=10}

//Mutável 

val newMenu :  MutableMap<String, Int> = mapOf("esfirra" to 2, "coquinha" to 3, "brigadeiro" to 10)

Para acessar um valor em um Map, podemos utilizar colchetes [] com sua chave, vamos supor que eu queria acessar o valor brigadeiro do map acima.

newMenu["brigadeiro"]

Aqui também conseguimos usar as funções add e remove.😉

Se quisermos verificar se uma chave específica já existe em um map, utilizamos a função .containsKey(). Exemplo:

novoMenu.containsKey("Quibe")
//false

Se quisermos obter as chaves ou valores de um Map, usamos as propriedades keys e values:

val menu = mapOf("coxinha" to 2, "coquinha" to 3, "batata" to 10)

menu.keys // [coxinha, coquinha, batata]
menu.values // [2, 3, 10]

keys e values são exemplos de propriedades de um objeto. Vamos falar mais disso na parte 2 desse conteúdo que será sobre Classes 😊

🧠 Agora faça os exercícios para praticar o que aprendemos até aqui

Expressões condicionais

🔸 No Kotlin, podemos tomar decisões utilizando as estruturas if ou when.

Esse tal de when foi uma novidade 😅.

Na documentação é fortemente recomendado utilizar o when, veja só:

Se você tiver que escolher entre ife when, recomendamos usar when, pois isso leva a programas mais robustos e seguros.

Usando o if:

Para usar o if, coloque a expressão condicional entre parênteses () e a ação a ser executada se o resultado for verdadeiro entre chaves {}:

val number: Int
val check = true

if (check) {
    number = 1
} else {
    number = 2
}

println(number) // O retorno será `1`

Usando when:

  • Use when quando você tiver uma expressão condicional com várias ramificações. When pode ser usado tanto como uma declaração quanto como uma expressão.
  • Aqui está um exemplo de como usar when como uma declaração:
  • Coloque a expressão condicional entre parênteses () e as ações a serem executadas dentro de chaves {}.
  • Use ” -> ” em cada ramificação para separar cada condição de cada ação.
val text = "Hello"

when (text) {
    // Verifica se o text é igual "1"
    "1" -> println("One")
    // Verifica se o text é igual a "Hello"
    "Hello" -> println("Greeting")
    // Declaração padrão
    else -> println("Unknown")     
}
// Saída: Greeting

👽 A estrutura when em Kotlin é semelhante ao switch-case em JavaScript, por exemplo. 🙂

Usando o when como expressão, atribuímos isso a uma variável. Veja só:

val number: Int
val check = true

number = when {
    check -> 1
    else -> 2
}

Legal demais, né?

Se usamos o when como uma expressão, o else é obrigatório, a menos que o compilador possa detectar que todos os casos possíveis estão cobertos pelas condições implementadas.

O when também é útil quando você precisa verificar uma cadeia de expressões booleanas, vamos dar uma olhada:

val temp = 18

val description = when {
    // Se temp < 0 for true, description recebe "very cold"
    temp < 0 -> "very cold"
    // Se temp < 10 for true, description recebe "a bit cold"
    temp < 10 -> "a bit cold"
    // Se temp < 20 é true, description recebe "warm"
    temp < 20 -> "warm"
    // description recebe "hot" caso não caia em nenhuma condição acima
    else -> "hot"             
}
println(description)
// warm

Ranges

🔸 Em Kotlin, os ranges são uma maneira de definir intervalos de valores. Eles são usados principalmente com tipos que podem ser comparados, como números e caracteres.

Um range é definido usando o operador “..” (que é chamado de operador de range) e pode ser usado para criar intervalos fechados ou abertos. Vamos dar uma olhada em alguns exemplos:

val closedRange = 1..5
for (i in closedRange) {
    println(i)
}
// Isso imprimirá 1, 2, 3, 4, 5

Uma coisa daora sobre ranges é que você pode criar ranges de caracteres ou substrings de strings. Veja só:

val charRange = 'a'..'z'
for (char in charRange) {
    println(char)
}
// Isso imprimirá todas as letras minúsculas de 'a' a 'z'

Agora criando um range de substrings a partir de uma string:

val str = "Hello, Kotlin"
val substringRange = str.substring(0..4)
println(substringRange) // Isso imprimirá "Hello"

Loops

🔸 No Kotlin, temos estruturas como o while, que permite continuar uma ação até que uma determinada condição seja satisfeita, e o for, que é utilizado para iterar um número específico de vezes, executando ações.

Vamos explorar um pouco mais essas duas estruturas.

Imagine que eu queria criar um looping que itera 5 vezes. Para isso poderia fazer um laço for:

For

for (number in 1..5) { 
    print(number)
}
// irá imprimir: 12345

Eu posso querer percorrer uma lista que contém sabores de bolos:

val cakes = listOf("chocolate", "baunilha", "milho")

for (cake in cakes) {
    println(cake)
}
// Isso irá imprimir cada um dos sabores da lista `cakes`.

While

🔸 Como em outras linguagens podemos utilizar o while de duas maneiras:

  1. Para executar um bloco de código enquanto uma expressão condicional é verdadeira. while
  2. Para executar o bloco de código primeiro e depois verificar a expressão condicional. do-while

💠 No primeiro caso: while:

var cakesEaten = 0
while (cakesEaten < 3) {
    println("Comeu um bolo")
    cakesEaten++
}

// Comer um bolo
// Comer um bolo
// Comer um bolo

💠 No segundo caso: do-while:

var cakesEaten = 0
var cakesBaked = 0
while (cakesEaten < 3) {
    println("Comeu um bolo")
    cakesEaten++
}
do {
    println("assou um bolo")
    cakesBaked++
} while (cakesBaked < cakesEaten)
// Comer um bolo
// Comer um bolo
// Comer um bolo
// asse um bolo
// asse um bolo
// asse um bolo

No código acima, temos duas variáveis, cakesEaten e cakesBaked, que estão sendo usadas para controlar o número de bolos consumidos e assados. Bora ver o que está acontecendo passo a passo:

  1. Inicialmente, ambas as variáveis cakesEaten e cakesBaked estão definidas como 0.
  2. Em seguida, há um loop while que continua até que o valor de cakesEaten seja menor que 3. Dentro desse loop, a mensagem “Eat a cake” é impressa na tela usando println, e então o valor de cakesEaten é incrementado em 1.
  3. O loop while continuará a ser executado até que cakesEaten seja igual ou maior que 3. Isso significa que o loop será executado três vezes, resultando na impressão de “Comer um bolo” três vezes e no incremento de cakesEaten para 3.
  4. Após a saída do primeiro loop, há um segundo loop do-while. Este loop imprime a mensagem “Asse um bolo” na tela usando println, e então o valor de cakesBaked é incrementado em 1.
  5. O loop do-while continuará a ser executado até que o valor de cakesBaked seja menor do que o valor de cakesEaten. Isso significa que o loop será executado três vezes, uma vez que cakesBaked é inicializado como 0 e cakesEaten é igual a 3 após a conclusão do primeiro loop. Portanto, o loop imprime “Asse um bolo” três vezes e incrementa cakesBaked para 3.

🧠 Agora faça os exercícios para praticar o que aprendemos até aqui

Funções

Usamos a palavra reservada fun para declarar uma função. Divertido, né?🤪

fun hello() {
    return println("Hello, world!")
}

fun main() {
    hello()
    // Hello, world!
}

Fizemos algo parecido igual no início desse conteúdo, lembra?! 😅

Em Kotlin:

  • os parâmetros da função são escritos entre parênteses ().
  • cada parâmetro deve ter um tipo e vários parâmetros devem ser separados por vírgulas ,.
  • o tipo de retorno é escrito após os parênteses da função (), separados por dois pontos :.
  • o corpo de uma função é escrito entre chaves {}.(Igual no JavaScript rs)
  • O return é usado para sair ou retornar algo de uma função.

Veja um exemplo:

fun sum(x: Int, y: Int): Int {
    return x + y
}

fun main() {
    println(sum(1, 2))
    // 3
}
  1. A primeira função é chamada sum e recebe dois parâmetros inteiros (x e y) e retorna um valor inteiro. O que essa função faz é simples: ela pega os valores de x e y, soma, em seguida, retorna o resultado da soma.
  2. A segunda função é chamada main. Ela é a função de entrada do programa e é onde a execução começa. Dentro da função main, nós chamamos a função sum(1, 2), que calcula a soma de 1 e 2 (resultando em 3) e, em seguida, usamos a função “println” para imprimir o resultado.

Nomeando argumentos

Incluir nomes de parâmetros torna seu código mais fácil de ler. Se você incluir nomes de parâmetros, poderá escrevê-los em qualquer ordem.

fun printMessageWithPrefix(message: String, prefix: String) {
    println("[$prefix] $message")
}

fun main() {
    // Uses named arguments with swapped parameter order
    printMessageWithPrefix(prefix = "Log", message = "Hello")
    // Isso imprime: [Log] Hello
}

Valores de parâmetro padrão

fun printMessageWithPrefix(message: String, prefix: String = "Info") {
    println("[$prefix] $message")
}

Caso nenhum valor seja passado para o parâmetro prefix, o valor padrão será “Info”.

fun main() {

    printMessageWithPrefix("Hello", "Log") 
    // [Log] Hello


    printMessageWithPrefix("Hello")        
    // [Info] Hello

    printMessageWithPrefix(prefix = "Log", message = "Hello")
    // [Log] Hello
}

👀 Você pode pular parâmetros específicos com valores padrão, em vez de omiti-los. No entanto, após pular o primeiro parâmetro, você deve nomear todos os parâmetros subsequentes.

Função sem retorno

💠 Se sua função não retorna um valor útil, o tipo de retorno dela é Unit. Unit é um tipo com apenas um valor – Unit.

Você não precisa declarar explicitamente que a função retorna Unit em seu corpo de função. Isso significa que você não precisa usar a palavra-chave return ou declarar um tipo de retorno, vamos ver alguns exemplos:

fun printMessage(message: String) {
    println(message)
    // `return Unit` ou `return` é opcional
}

fun main() {
    printMessage("Hello")
    // Hello
}

Funções single-expression

🔸 Para tornar nosso código mais conciso, podemos usar funções de “única expressão”. Por exemplo, podemos encurtar a nossa função sum() desse jeito aqui:

// antes:

fun sum(x: Int, y: Int): Int {
    return x + y
}

// depois:

fun sum(x: Int, y: Int) = x + y

Você pode remover as chaves {} e declarar o corpo da função usando o operador de atribuição =. E devido à inferência de tipos do Kotlin, você também pode omitir o tipo de retorno. A função sum() se torna então uma única linha 😱

👀 Omissão do tipo de retorno é apenas possível quando sua função não possui corpo ({}), a menos que o tipo de retorno de sua função seja Unit.

🧠 Agora faça os exercícios para praticar o que aprendemos até aqui

💎 Bônus

Nessa parte bônus, irei explicar como fazer o download do IntelliJ IDEA gratuitamente e como aproveitar ao máximo essa ferramenta para aprimorar seus conhecimentos em Kotlin, através de prática direta na própria IDE 😻

👁 Antes de instalar o IntelliJ IDEA, tenha certeza que o JDK está instalado na sua máquina. Você pode baixar o JDK mais recente diretamente do site da Oracle ou optar por uma distribuição OpenJDK, que é uma alternativa de código aberto. Certifique-se de fazer todas as configurações necessárias.

  • Baixe o IntelliJ aqui nesse link. Informação importante: A primeira opção que aparece é a Ultimate, não é essa que queremos de um scroll para baixo e faça o download da Community Edition.
  • Depois de baixar, siga todos os procedimentos de acordo com seu sistema operacional.

Quando você abrir o IntelliJ IDEA, provavelmente você terá algo parecido com isso daqui:

Print da IDE IntelliJ mostrando a página inicial da IDE

Se quisermos criar um novo projeto Kotlin, podemos clicar em new project e aqui não tem muito segredo, você deve escolher um nome para seu projeto e colocar a linguagem desejada, que no nosso caso é o Kotlin e logo após clicar em create.

Usando a IDE para aprender/praticar Kotlin 🤯

  • Na tela inicial, à esquerda, clique em “Learn”.
  • Em seguida, localize e clique em “New Course” no lado direito.
  • Após clicar em “New Course”, uma nova página será aberta. No lado esquerdo, clique em “Marketplace”. Neste caso, estou fazendo o seguinte curso.

print da IDE IntelliJ mostrando a parte de cursos e desafios, circulando o curso kotlin Koans, demonstrando qual curso eu selecionei

  • Depois de escolher, clique em Open e isso o levará para uma página que inclui uma série de desafios, veja só:

print da tela de courses da IDE IntelliJ

  • À esquerda, você encontrará uma lista de todos os desafios propostos.
  • No centro é onde você irá resolver esses desafios, ou seja, onde você irá codar.
  • À direita, você encontrará a descrição do desafio, ou seja, as instruções sobre o que precisa ser feito.

Depois que finalizar o desafio para verificar se está correto e prosseguir para o próximo, basta clicar em check.

print da tela de courses da IDE IntelliJ

Chegamos ao fim desta primeira parte, espero que tenham gostado!

Até a próxima e bons estudos!

Se você leu até o final reage com um 💟 se não, não precisa reagir :(.

The post Explorando os Conceitos Básicos do Kotlin: Parte I appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/10/29/explorando-os-conceitos-basicos-do-kotlin-parte-i/feed/ 0
Are Tech Industry Layoffs Reflecting New Tech Landscape Realities? https://prodsens.live/2023/10/22/are-tech-industry-layoffs-reflecting-new-tech-landscape-realities/?utm_source=rss&utm_medium=rss&utm_campaign=are-tech-industry-layoffs-reflecting-new-tech-landscape-realities https://prodsens.live/2023/10/22/are-tech-industry-layoffs-reflecting-new-tech-landscape-realities/#respond Sun, 22 Oct 2023 02:25:44 +0000 https://prodsens.live/2023/10/22/are-tech-industry-layoffs-reflecting-new-tech-landscape-realities/ are-tech-industry-layoffs-reflecting-new-tech-landscape-realities?

Are evolving tech trends and shifts causing tech layoffs? How could this affect innovation and competition? How are…

The post Are Tech Industry Layoffs Reflecting New Tech Landscape Realities? appeared first on ProdSens.live.

]]>
are-tech-industry-layoffs-reflecting-new-tech-landscape-realities?

Are evolving tech trends and shifts causing tech layoffs? How could this affect innovation and competition? How are those impacted adapting? We’re eager to hear your insights.

The post Are Tech Industry Layoffs Reflecting New Tech Landscape Realities? appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/10/22/are-tech-industry-layoffs-reflecting-new-tech-landscape-realities/feed/ 0
⚠️ Don’t try this at home: A CMS written in Bash ONLY?? https://prodsens.live/2023/09/03/%e2%9a%a0%ef%b8%8f-dont-try-this-at-home-a-cms-written-in-bash-only/?utm_source=rss&utm_medium=rss&utm_campaign=%25e2%259a%25a0%25ef%25b8%258f-dont-try-this-at-home-a-cms-written-in-bash-only https://prodsens.live/2023/09/03/%e2%9a%a0%ef%b8%8f-dont-try-this-at-home-a-cms-written-in-bash-only/#respond Sun, 03 Sep 2023 17:25:39 +0000 https://prodsens.live/2023/09/03/%e2%9a%a0%ef%b8%8f-dont-try-this-at-home-a-cms-written-in-bash-only/ ️-don’t-try-this-at-home:-a-cms-written-in-bash-only??

Here we go again. After building an image modal with CSS only (and completely neglecting accessibility (sorry, @grahamthedev))…

The post ⚠️ Don’t try this at home: A CMS written in Bash ONLY?? appeared first on ProdSens.live.

]]>
️-don’t-try-this-at-home:-a-cms-written-in-bash-only??

Here we go again.

After building an image modal with CSS only (and completely neglecting accessibility (sorry, @grahamthedev)) and an attempt to establish CSS as a backend language (although it worked, you people didn’t like it very much for some reason. I wonder why.), we’re finally back with stuff you and I probably shouldn’t ever do.

Today: Let’s use Bash (yes, Bash) to create a CMS!

Pascal no

Pascal yes! Pascal always yes!

To give credit where credit is due: This idea came from a funny discussion with a co-worker about how to overcomplicate stuff. He came up with a “bash server”, and we started to exaggerate it more and more until I said, “Challenge accepted,” and here we are.

Disclaimer: We’ll neglect security, apart from some password encryption and most best practices. This tool will be something I’ll never ever ever use in production, and you, dear reader, should not do it either. Please. There. You’ve been warned.

Defining what it does

We’ll create a very basic CMS:

  • A user can log in and log out (so we need users and session handling)
  • A logged-in user can create, update and delete pages
  • An anonymous user can read all pages
  • A page consists of a navigation title, a route path, some markup and a flag if it should show up in the main navigation

However, to use Bash as a backend language, we first need to get it to handle HTTP requests. Luckily, there are Bash utilities we can use to listen to TCP requests and send responses, most notably netcat. We “only” need to parse a request and generate a response.

Once that’s working, we’ll use SQLite to load the requested page and render its markup.

Let’s move on to the first bits of code.

The database schema

The boring bits first. We’ll use the following database schema for our SQLite database and add a few default records:

CREATE TABLE IF NOT EXISTS pages (
  routePath TEXT NOT NULL,
  navTitle TEXT,
  isInMainNavigation BOOLEAN NOT NULL,
  markup TEXT NOT NULL
);

INSERT INTO pages VALUES
('/', 'Home', 1, '

Hello, Bash CMS!

'
), ('/about', 'About', 1, '

About

This page was created entirely with BashCMS!

Learn more

'
), ('/about/bash-cms', NULL, 0, '

About BashCMS

BashCMS is a CMS entirely written in Bash!

'
); CREATE TABLE IF NOT EXISTS users ( username TEXT NOT NULL, password TEXT NOT NULL /* Hash generated with sha256sum */ ); INSERT INTO users VALUES ('admin', 'fc8252c8dc55839967c58b9ad755a59b61b67c13227ddae4bd3f78a38bf394f7'); /* pw: admin */ CREATE TABLE IF NOT EXISTS sessions ( sessId TEXT NOT NULL, userRowId INTEGER );

We can access the database via the sqlite3 CLI tool, which we can feed with data from our Bash script.

The actual server

Let’s start with the Bash part now. To listen to HTTP requests, we use Netcat. We’ll be using the OpenBSD Netcat version.

In the listen mode, Netcat is interactive. It prints out the request details (i.e. the headers, the body, the HTTP method and all) on STDOUT and expects the user to write the response in the STDIN.

For those unfamiliar with Linux/Bash, STDIN and STDOUT are the default ways to communicate with a program. What we see in the terminal is usually STDOUT, and the keyboard input is STDIN. A program is allowed to read from STDIN and write to STDOUT.

Once we send something to Netcat, it sends that over the wire and terminates. This means that we can only handle a single request at a time. For the server to run continuously, we need to start Netcat again and let it listen after it has terminated.

To read and write from Netcat, we also need a way to programmatically read STDOUT and write to STDIN. We can do this using a utility called coproc, which executes a given command asynchronously in a subshell. We do nothing as long as Netcat is waiting for some incoming requests. Only once Netcat starts to write to the STDOUT do we start reading and save it to a variable.

There is, however, one small problem: Netcat does not tell us if and when it’s finished writing to STDOUT. We need to determine that ourselves. The most straightforward approach is to wait for an empty new line and stop there.

We basically end up with a structure like this:

while true # You know your script will be fun when it starts with an endless loop.
do
  coproc nc -l -p 1440 -q1 -v # Spawns netcat such that we can read from and write to it

  REQ_RAW="" # This will contain the entire request
  IFS="" # Delimiter for `read`

  while read -r TMP; do # Read every line from STDOUT
    REQ_RAW+=$TMP$'n' # Append the line to the REQ variable

    # If the length of TMP is equal to one byte
    if [[ ${#TMP} -eq 1 ]] ; then
      break
    fi
  done <&"${COPROC[0]}" # Reads from the coproc STDOUT, line by line

  echo $REQ_RAW # Output the request for testing purposes

  kill "$COPROC_PID" # Kill the process for the subsequent request
  wait "$COPROC_PID" # Wait until it's actually gone
done

If you’re really unfamiliar with Bash, this looks intimidating. It might even do so for people who know Bash. I learned a lot during this experiment, and I am deeply convinced that Bash works very much like quantum physics: One does not understand Bash; one gets used to it.

Back to business… The “empty line” approach breaks down as soon as we want to read the HTTP body in case of a POST request. Luckily, HTTP knows a header called Content-Length that tells us the exact number of bytes.

This blows up the code for our server tremendously:

while true
do
  coproc nc -l -p 1337 -q1 -v # Spawns netcat such that we can read from and write to it. Listens on port 1337.

  REQ_RAW="" # This will contain the entire request
  IFS="" # Delimiter for `read`

  while read -r TMP; do
    REQ_RAW+=$TMP$'n' # Append the line to the REQ variable

    TMPLEN=$(echo $TMP|wc -c) # Figure out the length of $TMP in bytes

    # Deduct the length of the read bytes from the rest of the body length
    if [[ $BODYLENGTH -ge 0 ]]; then # Still some body left to read
      BODYLENGTH=$((BODYLENGTH - TMPLEN))
    fi

    # If the request has a body (determined by the header, which is usually the last one)
    # We continue reading the exact number of bytes
    if [[ "$TMP" =~ ^"Content-Length: " ]]; then
      BODYLENGTH=$(echo "$TMP"|grep -o '[[:digit:]]+')
      HAS_BODY=1
    fi

    # Read the entire body; abort reading
    if [[ $HAS_BODY -eq 1 ]] && [[ $BODYLENGTH -le 0 ]]; then
      break
    fi

    # No body but empty line encountered, abort reading
    if [[ $HAS_BODY -eq 0 ]] && [[ $TMPLEN -le 2 ]]; then
      break
    fi
  done <&"${COPROC[0]}" # Reads from the coproc STDOUT, line by line

  # Display the entire request for debugging
  echo $REQ_RAW

  kill "$COPROC_PID" # Kill the process for the subsequent request
  wait "$COPROC_PID" # Wait until it's actually buried
done

This works well already. We basically have a request logger now. Progress!

The anatomy of a HTTP request

We first need to parse the request to determine what the server should execute. Let’s look at what we’re dealing with.

A typical HTTP request is structured like this:

[Method] [Path + Query String] HTTP/[HTTP Version]
[Headers]

[Body]

When I perform a GET request on the server, it outputs something like this:

GET / HTTP/1.1
User-Agent: PostmanRuntime/7.29.0
Accept: */*
Cache-Control: no-cache
Host: localhost:1440
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

A POST request, on the other hand, could look like this:

POST / HTTP/1.1
User-Agent: PostmanRuntime/7.29.0
Accept: */*
Cache-Control: no-cache
Host: localhost:1440
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: multipart/form-data; boundary=--------------------------328683080620751780512479
Content-Length: 169

----------------------------328683080620751780512479
Content-Disposition: form-data; name="hello"

world
----------------------------328683080620751780512479--

We can work with this.

Adding some logic

The request is stored as a single string in a variable called REQ_RAW, so we can parse it using several other Bash utilities.

We create a function called parse_request and put that into a separate file to keep things organized. We then call this function after the reading loop:

#!/usr/bin/bash

source ./server/parse_request.sh

while true # Continue doing this, kind of like an event loop.
do
  coproc nc -l -p 1440 -q1 -v # Spawns netcat such that we can read from and write to it

  ## ...

  # Declare an associative array called `REQUEST`
  declare -A REQUEST=()

  parse_request $REQ_RAW REQUEST

  # Print the contents of the associative array
  declare -p REQUEST

  # Add more magic here

  kill "$COPROC_PID" # Kill the process for the subsequent request
  wait "$COPROC_PID" # Wait until it's actually gone
done

This function needs to do a few things at once:

  • Determine the HTTP method
  • Determine the route the user has requested
  • Parse out any GET variables (i.e. ?foo=bar, etc.)
  • Parse out the body
  • Parse out cookies

We can parse the very first line of the request to get the HTTP method and route path. Afterwards, we parse the cookies and check if we need to parse a body, which only happens on POST and PUT requests.

#
# Parses the entire request
#
function parse_request() {
  RAW_REQ=$1

  # This makes the REQUEST associative array available to write to
  # We need to make sure to not call it REQUEST, though, because
  # that name is already reserved in the outer scope
  declare -n INNER_REQ="$2"

  # Extract the request line: method, path (+ query string) and version
  REQUESTLINE=`echo "${RAW_REQ}" | sed -n 1p`
  IFS=' ' read -ra PARTS <<< "$REQUESTLINE"
  METHOD=${PARTS[0]}
  REQUEST_PATH=${PARTS[1]}

  # Split query string from the actual route
  IFS='?' read -ra REQUEST_PATH_PARTS <<< "$REQUEST_PATH"
  REQUEST_ROUTE=${REQUEST_PATH_PARTS[0]}
  QUERY_STRING=${REQUEST_PATH_PARTS[1]}

  if [[ "$QUERY_STRING" != "" ]]; then
    parse_query_string $QUERY_STRING INNER_REQ
  fi

  parse_cookies $RAW_REQ INNER_REQ

  # If we're dealing with either a POST or a PUT request, chances are there's a form body.
  # We extract that with the previously found $FORMDATA_BOUNDARY.
  if [[ "$METHOD" == "POST" ]] || [[ "$METHOD" == "PUT" ]]; then
    parse_body $RAW_REQ INNER_REQ
  fi

  INNER_REQ["METHOD"]="$METHOD"
  INNER_REQ["ROUTE"]="$REQUEST_ROUTE"
}

The query string parsing is pretty straightforward:

#
# Parses the query string and assigns it to the request object
#
function parse_query_string() {
  RAW_QUERY_STRING=$1
  declare -n REQ_ARR="$2"

  # Split the query parameters into a hashmap
  IFS='&' read -ra QUERYPARTS <<< "$QUERY_STRING"
  for PART in "${QUERYPARTS[@]}"; do
    IFS='=' read -ra KEYVALUE <<< "$PART"
    KEY=${KEYVALUE[0]}
    VALUE=${KEYVALUE[1]}
    REQ_ARR["QUERY","$KEY"]="$VALUE"
  done
}

And so is the cookie parsing:

#
# Parses cookies out of the request headers
#
function parse_cookies() {
  RAW_REQ_BODY=$1
  declare -n REQ_ARR="$2"

  COOKIE_LINE=`echo $RAW_REQ_BODY|grep 'Cookie:'`
  COOKIE=${COOKIE_LINE#"Cookie:"}

  if [[ "$COOKIE" != "" ]]; then
    IFS=';' read -r -d '' -a COOKIEPARTS <<< "$COOKIE"

    for PART in "${COOKIEPARTS[@]}"; do
      if [[ "$PART" != "" ]]; then
        IFS='=' read -ra KEYVALUE <<< "$PART"
        KEY=${KEYVALUE[0]//" "/""} # Remove all spaces, so we don't have leading spaces
        VALUE=${KEYVALUE[1]}
        REQ_ARR["COOKIE","$KEY"]=${VALUE::-1}
      fi
    done
  fi
}

In both functions, we carefully rip the necessary parts out of the entire request and split it by some characters, namely ? and = for the query string and ; and = for the cookies. We then remove some unnecessary spaces and write it to the REQUEST associative array.

Parsing the body is more complex. We’re dealing with the multipart/form-data format to allow for multi-line strings and, potentially, file uploads. I found it actually more straightforward to work with than any URL encoding.

#
# Parses the POST body and assigns it to the request object
#
function parse_body() {
  RAW_REQ_BODY=$1
  declare -n REQ_ARR="$2"

  FORM_BOUNDARY_LINE=`echo $RAW_REQ_BODY|grep 'Content-Type: multipart/form-data; boundary='`
  FORM_BOUNDARY=${FORM_BOUNDARY_LINE#"Content-Type: multipart/form-data; boundary="}

  # Replace the $FORMDATA_BOUNDARY with a single character so we can split with that.
  TMP_BODY_PARTS=`echo "${RAW_REQ_BODY//"$FORM_BOUNDARY"/$'§'}" | head -n -2` # We need to use _some_ character to use `read` here.

  IFS='§' read -r -d '' -a BODYPARTS <<< "$TMP_BODY_PARTS"

  for PART in "${BODYPARTS[@]}"; do
    KEY=`echo "${PART}" | grep -o -P '(?<=name=").*?(?=")'`
    if [[ "$KEY" != "" ]]; then
      VALUE=`echo "${PART}" | head -n -1 | tail -n +4`
      REQ_ARR["BODY","$KEY"]=${VALUE::-1}
    fi
  done
}

When we run the code now with our GET request from before, we get the following output from our Bash server:

declare -A REQUEST=([ROUTE]="https://dev.to/" [METHOD]="GET" )

(Yes, declare -p creates a declare -A statement, so one could execute that again to have the same associative array.)

The mentioned POST request would output this:

declare -A REQUEST=([BODY,hello]="world" [ROUTE]="https://dev.to/" [METHOD]="POST" )

Neat!

Reacting to the request

Similar to the REQUEST array, we declare a RESPONSE array. This array will contain the DOM we deliver, the status code, and some headers, like Set-Cookie or Location for redirects.

Since we need to be able to tell users apart (some are logged in and some are not), we implement a function called set_session. This generates a session ID, writes it to the SQLite database, and sets a session cookie. Any following request from the same client will send that same session ID cookie.

function set_session() {
  declare -n REQ="$1"
  declare -n RES="$2"

  if [[ "${REQ[COOKIE,SESSID]}" != "" ]]; then
    # SESSID cookie was already set once; reset it
    RES["COOKIES,SESSID"]="${REQ[COOKIE,SESSID]}"
  else
    # No SESSID cookie, so let's generate one
    SESSID=`echo $RANDOM | md5sum | head -c 20; echo;` # Taken from SO.

    # Save cookie into database
    sqlite3 db.sqlite "insert into sessions values ('${SESSID}', NULL);" ".exit"
    RES["COOKIES,SESSID"]="$SESSID"
  fi
}

Notice how we need both the REQ and the RES array: We already write to the RESPONSE array by setting a COOKIES key with a sub-key called SESSID.

We call this function after we call parse_request:

while true; do

  # Request reading shenanigans

  declare -A REQUEST=()
  declare -A RESPONSE=()
  parse_request $REQ_RAW REQUEST

  set_session REQUEST RESPONSE

  # More stuff later, don't worry

  kill "$COPROC_PID" # Kill the process for the subsequent request
  wait "$COPROC_PID" # Wait until it's actually gone
done

Next, we can implement a function to react to the actual request. We call it render_cms_page. In there, we look in the database for any entry with a route that matches the route from the request:

function render_cms_page() {
  REQUEST=$1
  declare -n RES="$2"

  DOM=`sqlite3 db.sqlite "select markup from pages where routePath='${REQUEST[ROUTE]}';" ".exit"`

  if [[ "$DOM" == "" ]]; then
    RES["BODY"]=`render_response "Not found."`
    RES["STATUS"]="404 Not found"
  else
    RES["BODY"]=`render_response $DOM`
    RES["STATUS"]="200 OK"
  fi
}

You might notice the render_response function in there, too. We use that to generate all of the surrounding HTML, such as a page header and navigation and some CSS:

function render_response() {
  DOC_START=`doc_start $1`
  PAGE_HEADER=`page_header`
  DOC_END=`doc_end`

  cat <<EOF
    $DOC_START
    $PAGE_HEADER

    
$2
$DOC_END EOF }

In there, however, we have the functions doc_start, page_header and doc_end:

function doc_start() {
  cat <<EOF


  
    
    </span><span class="nv">$1</span><span class="sh">
    
    
  
  
EOF
}

function doc_end() {
  cat <<EOF
  

EOF
}

function page_header() {
  # Fetch header-relevant pages
  cat <<EOF
  

Bash CMS

EOF }

And with that, we’re almost done.

The last step to an actual response is to render a response string. Much like an HTTP request, a response is a single multi-line string with different parts. We only need to assemble it correctly:

function generate_response_string() {
  declare -n RES="$1"

  # Transform cookie entries into Set-Cookie headers
  COOKIES=""
  for RESKEY in "${!RES[@]}"; do
    if [[ "$RESKEY" =~ ^"COOKIES," ]]; then
      COOKIE_NAME=${RESKEY#"COOKIES,"}
      COOKIES+="Set-Cookie: $COOKIE_NAME=${RES[$RESKEY]}
" # Adds a newline after this Set-Cookie header.
    fi
  done

  RES["CONTENT_TYPE"]="text/html"
  RES["HEADERS","Content-Type"]="${RES[CONTENT_TYPE]}; charset=UTF-8"
  RES["HEADERS","Server"]="Bash. Please don't send cat /etc/passwd as a cookie because hacking is bad :("

  HEADERS=""
  for RESKEY in "${!RES[@]}"; do
    if [[ "$RESKEY" =~ ^"HEADERS," ]]; then
      HEADER_NAME=${RESKEY#"HEADERS,"}
      HEADERS+="${HEADER_NAME}: ${RES[$RESKEY]}
" # Adds a newline after this Set-Cookie header.
    fi
  done

  # declare -p RES

  cat <<EOF
HTTP/1.1 ${RES[STATUS]}
${COOKIES::-1}
${HEADERS}

${RES[BODY]}
EOF
}

And we’re good to go. Let’s see what this does:

A header, navigation and the content from the  raw `/` endraw  page!

(On a side note: Using backticks anywhere is making me nervous now. Who knows what it’ll execute…)

Adding the routes

Now that we’ve implemented the dynamic routes let’s take care of the static ones, such as /login, /edit, /add-new-page, /logout and /delete. For that, we add two more functions: One for the login form and one for the edit form:

function render_login_page() {
  cat <<EOF
  
$1">
EOF } function render_edit_form() { NAVTITLE=$1 IS_IN_MAIN_NAVIGATION="" ROUTEPATH=$3 DOM=$4 if [[ "$2" == "1" ]]; then IS_IN_MAIN_NAVIGATION=" checked" fi cat <<EOF
$NAVTITLE"> $ROUTEPATH">
EOF }

And lastly, we expand the render_cms_page function:

function render_cms_page() {
  REQUEST=$1
  declare -n RES="$2"

  if [[ "${REQUEST[ROUTE]}" == "https://dev.to/login" ]]; then
    if [[ "${REQUEST[METHOD]}" == "POST" ]]; then
      USERNAME=${REQUEST[BODY,username]}
      PASSWORD=`echo ${REQUEST[BODY,password]} | sha256sum`
      USERID=`sqlite3 db.sqlite "select rowid from users where username='$USERNAME' and password='${PASSWORD::-3}'"`

      if [[ "$USERID" == "" ]]; then
        DOM=`render_login_page $USERNAME`
        DOM+="

Username or password incorrect

"
RES["BODY"]=`render_response "Login" $DOM` RES["STATUS"]="200 OK" else sqlite3 db.sqlite "update sessions set userRowId = $USERID where sessId = '${REQUEST[COOKIE,SESSID]}'" RES["STATUS"]="307 Temporary Redirect" RES["HEADERS","Location"]="/" fi else DOM=`render_login_page` RES["BODY"]=`render_response "Login" $DOM` RES["STATUS"]="200 OK" fi DOM=`render_login_page ${REQUEST[BODY,username]}` elif [[ "${REQUEST[ROUTE]}" == "https://dev.to/logout" ]]; then sqlite3 db.sqlite "update sessions set userRowId = NULL where sessId = '${REQUEST[COOKIE,SESSID]}'" RES["STATUS"]="307 Temporary Redirect" RES["HEADERS","Location"]="/" elif [[ "${REQUEST[ROUTE]}" == "https://dev.to/add-new-page" ]]; then if [[ "${REQUEST[METHOD]}" == "POST" ]]; then IS_IN_MAIN_NAVIGATION="0" if [[ "${REQUEST[BODY,is_in_navigation]}" == "1" ]]; then IS_IN_MAIN_NAVIGATION="1" fi sqlite3 db.sqlite "insert into pages values ('${REQUEST[BODY,routepath]}', '${REQUEST[BODY,navtitle]}', ${IS_IN_MAIN_NAVIGATION}, '${REQUEST[BODY,dom]}');" ".exit" RES["STATUS"]="307 Temporary Redirect" RES["HEADERS","Location"]="${REQUEST[BODY,routepath]}" else DOM=`render_edit_form` RES["BODY"]=`render_response "New page" $DOM` RES["STATUS"]="200 OK" fi elif [[ "${REQUEST[ROUTE]}" == "https://dev.to/edit" ]]; then LOGGEDIN_USERID=`sqlite3 db.sqlite "select userRowId from sessions where sessId = '${REQUEST[COOKIE,SESSID]}'" ".exit"` if [[ "$LOGGEDIN_USERID" == "" ]]; then RES["STATUS"]="403 Forbidden" RES["BODY"]=`render_response "Nope" "Not allowed to do that"` else if [[ "${REQUEST[METHOD]}" == "POST" ]]; then IS_IN_MAIN_NAVIGATION="0" if [[ "${REQUEST[BODY,is_in_navigation]}" == "1" ]]; then IS_IN_MAIN_NAVIGATION="1" fi sqlite3 db.sqlite "update pages set routePath='${REQUEST[BODY,routepath]}', navTitle='${REQUEST[BODY,navtitle]}', isInMainNavigation=${IS_IN_MAIN_NAVIGATION}, markup='${REQUEST[BODY,dom]}' where routePath='${REQUEST[QUERY,route]}';" ".exit" RES["STATUS"]="307 Temporary Redirect" RES["HEADERS","Location"]="${REQUEST[BODY,routepath]}" else PAGE=`sqlite3 db.sqlite "select navTitle, isInMainNavigation, routePath, markup from pages where routePath='${REQUEST[QUERY,route]}'"` IFS='|' read -r -d '' -a PAGEPARTS <<< "$PAGE" DOM=`render_edit_form ${PAGEPARTS[0]} ${PAGEPARTS[1]} ${PAGEPARTS[2]} ${PAGEPARTS[3]}` RES["BODY"]=`render_response "Edit" $DOM` RES["STATUS"]="200 OK" fi fi elif [[ "${REQUEST[ROUTE]}" == "https://dev.to/delete" ]]; then LOGGEDIN_USERID=`sqlite3 db.sqlite "select userRowId from sessions where sessId = '${REQUEST[COOKIE,SESSID]}'" ".exit"` if [[ "$LOGGEDIN_USERID" == "" ]]; then RES["STATUS"]="403 Forbidden" RES["BODY"]=`render_response "Nope" "Not allowed to do that"` else sqlite3 db.sqlite "delete from pages where routePath='${REQUEST[QUERY,route]}';" ".exit" echo "delete from pages where routePath='${REQUEST[QUERY,route]}';" RES["STATUS"]="307 Temporary Redirect" RES["HEADERS","Location"]="/" fi else DOM=`sqlite3 db.sqlite "select markup from pages where routePath='${REQUEST[ROUTE]}';" ".exit"` LOGGEDIN_USERID=`sqlite3 db.sqlite "select userRowId from sessions where sessId = '${REQUEST[COOKIE,SESSID]}'" ".exit"` if [[ "$LOGGEDIN_USERID" != "" ]]; then DOM+="" fi if [[ "$DOM" == "" ]]; then RES["BODY"]=`render_response "Not found" "Not found."` RES["STATUS"]="404 Not found" else RES["BODY"]=`render_response "Bash CMS!" $DOM` RES["STATUS"]="200 OK" fi fi }

And we’re good. With 443 lines of code, we’ve written a basic CMS from scratch in Bash only!

Demo time!

(The gif might take a few seconds to load…)

The BashCMS in action!

Q&A time!

Q: Does it perform well?

A: No. Not at all. This script can handle a single request at a time. Even Apache can handle several hundred connections at once.

Q: Should I use this…

A: No. Please, for the love of everything, don’t.

Q: Does the font need to be monospaced? That’s so 1990s

A: Yes. We’re using Bash, so why shouldn’t it be monospaced?

Q: Anything else?

A: I use Arch, by the way.

I hope you enjoyed reading this article as much as I enjoyed writing it! If so, leave a ❤! I write tech articles in my free time and like to drink coffee every once in a while.

If you want to support my efforts, you can offer me a coffee ☕ or follow me on Twitter 🐦! You can also support me directly via Paypal!

Buy me a coffee button

The post ⚠️ Don’t try this at home: A CMS written in Bash ONLY?? appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/09/03/%e2%9a%a0%ef%b8%8f-dont-try-this-at-home-a-cms-written-in-bash-only/feed/ 0
Business Process Automation is Construction Managements Opportunity to Improve ROI https://prodsens.live/2023/08/05/construction-managements-opportunity-to-improve-roi-4/?utm_source=rss&utm_medium=rss&utm_campaign=construction-managements-opportunity-to-improve-roi-4 https://prodsens.live/2023/08/05/construction-managements-opportunity-to-improve-roi-4/#respond Sat, 05 Aug 2023 18:25:56 +0000 https://prodsens.live/2023/08/05/construction-managements-opportunity-to-improve-roi-4/ business-process-automation-is-construction-managements-opportunity-to-improve-roi

Executive Summary Construction management firms face many challenges: resource management, procurement, payments, outdated or lack of digital tools,…

The post Business Process Automation is Construction Managements Opportunity to Improve ROI appeared first on ProdSens.live.

]]>
business-process-automation-is-construction-managements-opportunity-to-improve-roi

Executive Summary

Construction management firms face many challenges: resource management, procurement, payments, outdated or lack of digital tools, etc. To withstand the risk, construction firms must find ways to gain efficiencies and maximize their resources. We discuss how Automating Business Processes will increase efficiency and help in cross-functional collaboration and how your employees, contractors, and sub-contractors communicate.

Construction Management Challenges for 2023 

In 2023, construction management firms face many challenges: resource management, procurement, payments, outdated or lack of digital tools, etc. To withstand the risk, construction firms must find ways to gain efficiencies and maximize their resources because, despite the challenges, the construction industry is one of the most significant contributors to the world’s GDP, adding a weighty 0.73 percent globally.

Construction Project Challenges

Construction Project Challenges

 Another factor noted by Dr. Algan Tezel, a lecturer in Construction Management, Civil Engineering, and Lean Construction, is that 80% of the construction industry comprises small and medium-sized enterprises or businesses (SMEs or SMBs), often working as sub-contractors for larger firms. 

A McKinsey study shows that 98% of construction projects are over budget, 77% are delayed, and efficiency rates consistently hover around 30%. The enormous amount of wasted time, money, and labor substantially negatively impacts the construction industry. 

When working on construction projects, it is essential to manage efficiently. However, there are several inefficiencies and challenges that every project manager often encounters.  

10 Most Common Inefficiencies in Construction Projects  

1. Budget Constraints

The budget is estimated based on stakeholder expectations. Project managers are responsible for setting reasonable expectations for cost overruns and making reconciliations to alleviate them. A miscalculation or inadequate oversight could lead to project ruin. There are budget factors that the project manager cannot control, such as environmental conditions, scarcity of resources and workforce, etc. Therefore, the budget must be constantly monitored. 

2. Time Management

Time constraints are the most significant problem resulting in defective designs, less revenue, and high accident rates. Project managers must identify the variables that cause delays and design workflows to meet deadlines. 

3. Safety Issues

Workers need to be trained in safety, as accidents can be prevented by strictly applying safe work practices. 

4. Lack of Well-Defined Objectives

When goals are not clearly defined, resources, time and money are wasted. Project managers must maintain good communication with the client to avoid unnecessary delays and help them develop and agree on these objectives. Sometimes stakeholders need a clear idea of what they disagree with or want.  

5. Inadequate Risk Management

Project managers must have the right skills to identify potential problems and know how to solve or eliminate them. The project needs proper risk management to avoid delays or going over budget. 

6. Inefficient Communication

Lack of communication means that essential work is lost, and the team is unaware of problems until it is too late to rectify them. Project managers should give clear guidelines and establish a scale that informs the team of progress and obstacles at the end of each day. These straightforward guidelines will allow problems to be identified early and rectified in time. 

7. Unrealistic Expectations

Sometimes stakeholders make unreasonable requests, such as speeding up projects or limiting the budget. These requests have a very negative influence on productivity. Therefore, project managers must respond to them after getting feedback from their team. 

8. Limited Skills in Personnel

According to Home Builders Institute’s Report, a total of 2.2. million new hires in construction are needed to meet demand through 2024. The industry faces two significant personal shortages regarding qualified workers, an aging workforce and a lack of skilled workers.  A lack of skills in construction teams can cause delays. The project manager must be aware of these shortcomings before they affect the project and try to remedy them as soon as possible. 

9. Lack of Structure

Performance management is a crucial issue. There must be clear objectives and job responsibilities. Therefore, everyone needs to have well-defined tasks to stay focused, and by breaking significant objectives into smaller, daily goals for each person, everything can be kept on track. 

10. Cash flow bottlenecks

National Subcontractor Market Report  highlights that slow payments contribute to 45% of their wasted resources, 41% reduced profit, and their failure to meet payroll 18% of the time. Late payments hurt the company’s cash flow and cause delays. 52% of subcontractors and 40% of material suppliers cite general contractor mismanagement as the source of payment problems.  

To overcome these inefficiencies and to accommodate the growth expected within the construction industry through 2024, Deloitte notes in its “The Future of Construction report that the industry will likely integrate more digital technologies into workstreams to boost production and efficiency. 

What is Workflow Automation, and Why is it Used? 

Workflow automation refers to the design, execution, and automation of processes based on workflow rules in which human tasks, data, or files are routed between people or systems in the fusion of predefined business rules.

Business Process Automation

Business Process Automation of Workflow

Typical project inefficiencies will see significant improvements through automating workflows in these critical areas: 

  • Productivity
  • Accuracy
  • Efficiency
  • Audibility
  • Job Satisfaction
  • Accountability

A  project management software tool is the solution to workflow automation and will help keep projects organized, streamline construction processes, and eliminate the inefficiencies discussed above.  

Workflow automation will allow workers to focus on managing their construction projects. The software takes care of many time-consuming tasks, such as invoicing, documentation management, incident reports, spreadsheets, communication between team members, etc. 

How can Inefficiency be Reduced in Construction with Project Management Software? 

How will a software solution help your organization’s bottom line and eliminate waste and inefficiencies?  

What are the benefits of using automation solutions to manage workflows?  

Configuring and implementing a workflow solution takes time, effort, and money. So knowing what waste and inefficiencies you are improving upon is essential. Some key benefits include the following: 

Improve Internal Communication

It is essential to maintain effective communication among workers to maintain operational efficiency. Good communication minimizes possible delays and losses. Using project management software, the project manager can communicate important information to workers, such as task start times, task flows, or changes that need to be made instantly on-site. 

Use Building Information Modeling (BIM)

BIM is a growing trend in the construction industry. Thanks to BIM technology, project managers can create digital representations of buildings before any actual physical work begins.  

These digital representations help contractors and subcontractors to visualize the structure and its most essential parts before it is built, making it possible to include the workflows required for construction.  

Likewise, conflicts between the various parties involved in the project (architects, structural engineers, electrical and plumbing installation engineers, etc.) can be visualized, enabling continuous communication between them and constant modification so that the final model matches reality as closely as possible. 

Record Productivity and Tracking

Project management software can help the project manager break down the overall project into smaller, more manageable phases to identify areas for improvement and monitor worker productivity.  

In addition, tracking allows you to see a breakdown of how each worker manages their time, so you can see how to improve their productivity. With this information, changes to the project can be made more efficiently, thereby increasing productivity and efficiency.  

Data Management Tools

Data management is essential for increasing efficiency in construction projects. Using project management software with a central database to collect site data helps project managers get a 360-degree view of what is happening at each stage of the project lifecycle and minimizes the likelihood of errors and delays. 

Improve the Planning Process

Far too often, the planning phase of a construction project is overlooked. It is, however, one of the critical factors in successful construction projects. When done accurately and carefully, project planning will help navigate unforeseen delays. Planning can also contribute to avoiding additional costs along the way.  

By using construction software in the planning process, all necessary information can be accessed centrally and allow project participants to be kept updated on any changes. 

Adopting On-Site Mobile Technology

In recent years, on-site mobile technology has been a growing trend in the construction industry. Using mobile technology, workers and project managers can communicate and share real-time updates on what is happening on site. It also reduces face-to-face contact, gives workers more time to complete their tasks, and increases efficiency in construction processes. 

Improving Your Company’s Bottom Line and Gaining a Positive ROI

The bottom line is why you make any strategic business decision. A business’s improvement activities always need to be justified, and executives always want to see a positive ROI (Return on Investment).  

Because the return from implementing different planning activities can negatively affect your bottom line, some tough questions always follow and is asked by the executive branch within an organization.  

Many construction management companies have been slow to adopt business process automation because adopting a new way of doing things takes planning, work, and training, which translates to a loss in billable hours and a real fear of making a negative investment for the company. 

However, the time may have come for management to consider these investments in digital solutions to offset rising costs and eliminate waste and inefficiencies within the supply chain, resource management, payments, and procurement to improve a business’s bottom line.  

With new mobile and cloud-centric technology solutions, project managers can access a fully integrated system across all platforms for a comprehensive project management solution.  

Workflow Automation Return on Investment

Investing In Business Process Automation

These software systems help eliminate time-consuming tasks such as invoicing, paperwork, bid management, and time sheets. Project management software helps the project manager improve efficiency and productivity by allowing contractors to self-complete those tedious tasks.   

Automating Business Processes will positively increase efficiency and help in cross-functional collaboration and how your employees, contractors, and sub-contractors communicate. Providing a central place also to find documentation associated with the correct project phase and other vital information to check on project phase completion or how much is left to complete. 

Eliminating these common risk factors that cause waste and inefficiency that negatively impact a company’s bottom line is the wisest investment your construction management company can make now. Rethinking how you do business and automating business processes is developing a new organizational mindset in cost reduction that, in turn, will make your business “recession-proof.” 

Ready to Change the Way You Do Business? 

An easy and simple workflow automation solution for an Agile environment is ClickUp, which is why we chose this PPM tool partner. The system is designed to replace & reduce the need for multiple productivity apps that might currently be used to run your business. The idea is to have one place for all your work and instantly bring your team together.

ClickUp has interviewed several of its customers to find out how they are using ClickUp to automate their business processes to improve their productivity and profitability. These case study stories highlight how adopting workflow automation helped these businesses embrace a cost-reduction mindset and eliminate high overhead costs and improve productivity by finding the inefficiency in the process that could be automated and save their company wasted man hours.  

Contact Kolme Group today to discuss how we can help you rethink how you do business with a Business Process Automation Solution that can meet your agile Construction Management business needs.

Contact Us Today

The post Business Process Automation is Construction Managements Opportunity to Improve ROI appeared first on Kolme Group.

The post Business Process Automation is Construction Managements Opportunity to Improve ROI appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/08/05/construction-managements-opportunity-to-improve-roi-4/feed/ 0
BRC20 Token – Trending and Booming Token Creation https://prodsens.live/2023/06/06/brc20-token-trending-and-booming-token-creation/?utm_source=rss&utm_medium=rss&utm_campaign=brc20-token-trending-and-booming-token-creation https://prodsens.live/2023/06/06/brc20-token-trending-and-booming-token-creation/#respond Tue, 06 Jun 2023 05:25:02 +0000 https://prodsens.live/2023/06/06/brc20-token-trending-and-booming-token-creation/ brc20-token-–-trending-and-booming-token-creation

The blockchain revolution has brought about significant changes to the way entrepreneurs conduct transactions online. With the advent…

The post BRC20 Token – Trending and Booming Token Creation appeared first on ProdSens.live.

]]>
brc20-token-–-trending-and-booming-token-creation

The blockchain revolution has brought about significant changes to the way entrepreneurs conduct transactions online. With the advent of the latest technologies, it has become easier to transact cryptocurrencies with anyone, anywhere in the world. One of the essential creations in this space is the BRC20 Token. The BRC20 token is now trending and booming in the crypto world.

What is BRC20 Token?

BRC20 Token is a specific token standard that is based on the Bitcoin blockchain. It is highly interoperable, which means that it can integrate with other blockchain-based applications and protocols. BRC20 Token is a vital aspect of the Bitcoin network. because it allows users to create their tokens and execute transactions on the blockchain.

Difference Between BRC20 Token and ERC20 Token

  • BRC-20 tokens are built on the Bitcoin blockchain, whereas ERC-20 tokens are built on the Ethereum blockchain.
  • BRC-20 tokens don’t make use of smart contracts, unlike ERC-20 tokens.
  • To mint and trade BRC-20 tokens, users need a Bitcoin wallet, whereas an Ethereum wallet is required for ERC-20 tokens.

In this article, we will be discussing the importance of creating a BRC20 Token and what it can do for your business.

Importance of Creating BRC20 Token

  1. Tokenization of assets
  2. Interoperability
  3. Functions of Smart Contracts
  4. Increased Security
  5. Increased Liquidity

1. Tokenization of assets

BRC20 Token is a non-fungible token standard. This means that you can create a token for your physical assets like real estate, gold, and diamonds, or your digital assets like music, art, and movies.

2. Interoperability

The BRC-20 token standard emphasizes interoperability, allowing easy integration with many blockchain platforms. This cross-chain interoperability fosters collaboration and creates opportunities for interesting new use cases.

3. Functions of smart contracts

The BRC-20 token will allow developers to harness the power of smart contracts to build highly decentralized applications. By automating and enforcing contracts, smart contracts eliminate the need for intermediaries, improving efficiency and transparency.

4. Increased Security

BRC20 Token is highly secure, and this is because once a transaction is executed, it is irreversible. Additionally, the blockchain network is built to be tamper-proof, which means that your transactions cannot be hacked or modified.

5. Increased Liquidity

BRC20 Token allows for fractional ownership of assets, making it easier for individuals to own parts of assets or even trade them in the open market. This creates more liquidity for the assets.

Therefore, BRC20 Token is an essential aspect of the Bitcoin blockchain ecosystem, and it provides an avenue for businesses to extend their reach, access new markets, and create innovative new solutions.

Now let us see…

How are BRC20 Tokens Used?

Here are some fantastic use cases for the BRC20 token,

1. Crowdfunding: Entrepreneurs and startups can use BRC20 tokens to raise capital from investors via crowdfunding campaigns. These tokens can be used as a medium of exchange or reward for backers, providing a new layer of transparency and accountability.

2. Loyalty programs: BRC20 tokens can be used to reward customers for their loyalty and engagement. Businesses can integrate these tokens into their existing loyalty programs for exclusive rewards and discounts.

3. Trading: BRC20 tokens can be listed on various crypto exchanges, allowing traders to buy, sell, and trade them for profit. This feature makes it a great option for businesses that want to create a liquid market for their tokens.

4. Asset Ownership: Businesses can use BRC20 tokens to represent ownership rights in assets such as real estate, stocks, and commodities. By tokenizing these assets, businesses can offer fractional ownership to investors without the need for traditional intermediaries.

5. Gaming: BRC20 tokens can be used within games to purchase in-game items and services, creating a new revenue stream for developers while providing gamers with an enhanced gaming experience.

In conclusion, the BRC20 token provides developers and businesses with a robust toolset to create a decentralized economy with its versatile use cases. By tokenizing assets, creating liquid markets, and incorporating them into loyalty programs, the BRC20 token is paving the way for a new generation of blockchain projects. So, when it comes to creating a new token standard for your next project, the BRC20 token is the best way to stand out in the crowded cryptocurrency space.

If you have not created a BRC20 Token for your business yet, now is the time to create a BRC20 token.

The post BRC20 Token – Trending and Booming Token Creation appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/06/06/brc20-token-trending-and-booming-token-creation/feed/ 0
Coming Soon: The State of Generative AI & How It Will Revolutionize Marketing [New Data + Expert Insights] https://prodsens.live/2023/04/18/coming-soon-the-state-of-generative-ai-how-it-will-revolutionize-marketing-new-data-expert-insights/?utm_source=rss&utm_medium=rss&utm_campaign=coming-soon-the-state-of-generative-ai-how-it-will-revolutionize-marketing-new-data-expert-insights https://prodsens.live/2023/04/18/coming-soon-the-state-of-generative-ai-how-it-will-revolutionize-marketing-new-data-expert-insights/#respond Tue, 18 Apr 2023 17:02:06 +0000 https://prodsens.live/2023/04/18/coming-soon-the-state-of-generative-ai-how-it-will-revolutionize-marketing-new-data-expert-insights/ coming-soon:-the-state-of-generative-ai-&-how-it-will-revolutionize-marketing-[new-data-+-expert-insights]

It’s almost here… Thanks for your interest in our upcoming Generative AI report and its corresponding pillar, “The…

The post Coming Soon: The State of Generative AI & How It Will Revolutionize Marketing [New Data + Expert Insights] appeared first on ProdSens.live.

]]>
coming-soon:-the-state-of-generative-ai-&-how-it-will-revolutionize-marketing-[new-data-+-expert-insights]

It’s almost here…

Thanks for your interest in our upcoming Generative AI report and its corresponding pillar, “The State of Generative AI & How It Will Revolutionize Marketing [New Data + Expert Insights]”.

If you’ve arrived on this page, we know our content so far has made you eager to see the full report. Check back on this same page on May 17, 2023, for our full report and corresponding blog posts.

We hope you enjoy what we’ve got in store for you! 

Worried you’ll forget? Click here or below to set a Google Calendar reminder that will notify you when the report is live.

state of generative AI coming soon pillar

Curious what’s in store? Here are a few topics we’ve got coming for you: 

  • Data from 1,350 U.S. professionals who work in marketing, sales, and service on how they’re using AI
  • The coolest jobs that could be created around AI
  • How to train your own teams to be better than bots 
  • How to handle AI ethics
  • Types of artificial intelligence and how marketers are using it
  • AI prompts to consider for marketers 

… and much, much more. 

Plus, hear from leaders at Jasper AI, Mention, Rock Content, and more. 

We’ll also send this content out in our Marketing Blog Newsletters, so be sure to subscribe to the HubSpot Marketing Blog by clicking the banner below and never miss a beat!

hubspot marketing blog

The post Coming Soon: The State of Generative AI & How It Will Revolutionize Marketing [New Data + Expert Insights] appeared first on ProdSens.live.

]]>
https://prodsens.live/2023/04/18/coming-soon-the-state-of-generative-ai-how-it-will-revolutionize-marketing-new-data-expert-insights/feed/ 0