Prévia do material em texto
Pensamento computacional para sistemas de larga escala Apresentação A partir da década de 1960, houve a popularização dos computadores como ferramentas para automatização de processos, pesquisa científica e automação. O software até então não tinha um papel de destaque, sendo toda a atenção destinada ao desenvolvimento do hardware. Com isso, novas demandas surgiram, com a necessidade de sistemas mais aplicados. A partir de então, em sistemas de larga escala, de folhas de pagamento até lançamentos de foguetes, o software começou a tomar conta do mercado. Com o aumento da complexidade dos sistemas e a falta de ferramentas adequadas para a construção, relatos de problemas relacionados ao software tornaram-se comuns. Erros que prejudicam a confiabilidade diminuíram a produtividade e, às vezes, representavam riscos de acidentes. Nesta Unidade de Aprendizagem, você vai saber como o Pensamento Computacional está relacionado com a construção de sistemas de larga escala e como surgiu a necessidade de definir princípios e padrões da engenharia de software para essa construção. Também serão discutidos as origens da engenharia de software e alguns tópicos sobre as dificuldades existentes no desenvolvimento de aplicações reais. Bons estudos. Ao final desta Unidade de Aprendizagem, você deve apresentar os seguintes aprendizados: Descrever a relação entre engenharia de software e Pensamento Computacional.• Listar princípios e padrões relevantes para a engenharia de software.• Determinar as dificuldades existentes no desenvolvimento de aplicações reais.• Desafio Princípios de projeto são importantes ferramentas da engenharia de software, as quais contêm um conjunto de sugestões e parâmetros para favorecer a manutenção e a evolução da aplicação. Mesmo que o projeto seja inicialmente pequeno, criá-lo de forma a reduzir a complexidade no momento de um possível aumento de escala diminui custos com o projeto e evita muitos problemas para a equipe de desenvolvimento. Diversos princípios são conhecidos, como os princípios DRY (Don't repeat yourself), KISS (Keep It Simple, Stupid), YAGNI (You aren't gonna need it) e SOLID (um acrônimo que une cinco regras de escrita, cada um representado por uma letra, que, ao final, formam a palavra "sólido", em inglês). Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. Considerando o trecho apresentado e a descrição do problema, qual princípio SOLID está sendo violado? Que alteração você sugere para adequar a funcionalidade? Infográfico Quanto maior a escala do sistema, mais se demanda o emprego de processos sistêmicos e metodologias para sua construção, manutenção e evolução. Nesse ponto, a engenharia de software tem por função recomendar e empregar princípios comuns às engenharias na construção de software. Diversos autores definiram princípios e padrões amplamente discutidos e difundidos por equipes de desenvolvimento, como os sete princípios de Pressman, os princípios SOLID, padrões GOF e padrões GRASP. Neste Infográfico, você vai conhecer os princípios SOLID para construção de software. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. Conteúdo do livro Desde sua proposição na década de 1960, a engenharia de software tem se empenhado na definição de processos, princípios e padrões para construção de software de qualidade, garantindo confiabilidade, produtividade e manutenção em sistemas de larga escala. Engenharia de software proporciona disciplina e procedimentos sistemáticos e quantificáveis, com foco no desenvolvimento, na usabilidade, na manutenção e na evolução de sistemas de software. Resumindo, a engenharia de software tem por função recomendar e empregar princípios comuns às engenharias na construção de software. No capítulo Pensamento Computacional para sistemas de larga escala, base teórica desta Unidade de Aprendizagem, você vai conhecer um pouco mais sobre as origens da engenharia de software e como a área se relaciona com o Pensamento Computacional, bem como os problemas enfrentados na construção de software e como a definição de princípios e padrões pode afetá-los. Boa leitura. PENSAMENTO COMPUTACIONAL OBJETIVOS DE APRENDIZAGEM > Descrever a relação entre engenharia de software e pensamento com- putacional. > Reconhecer princípios e padrões relevantes para a engenharia de software. > Determinar as dificuldades existentes no desenvolvimento de aplicações reais. Introdução Dos primórdios da computação, desde a tábua de calcular, até os grandes mainframes IBM, o hardware sempre foi o grande destaque. A história, po- rém, teve uma reviravolta por volta dos anos 1960, de forma que, atualmente, empresas de diversos tamanhos são dependentes de sistemas de informação que auxiliam em tomadas de decisão, automatização e gestão. Sistemas de grande escala estão mais inseridos em nosso cotidiano do que conseguimos perceber, na análise do comportamento de um usuário nas redes sociais, no controle dos aparelhos de uma aeronave ou simplesmente para pedir uma refeição pelo smartphone. Pensamento computacional para sistemas de larga escala Marcelo da Silva dos Santos Devido à importância do software atualmente, não é estranho que exista uma área da computação reservada à criação de estratégias para o desenvolvi- mento de aplicações, principalmente aquelas de larga escala e complexidade. A engenharia de software se dedica à criação de metodologias quantificáveis e sistemáticas para desenvolvimento, gerência, manutenção e escalabilidade em sistemas de software. Ou seja, sua intenção é definir princípios e padrões da engenharia para desenvolvimento de software. Neste capítulo, você vai conhecer a área de engenharia de software, com destaque para sua relação com o pensamento computacional. Também serão apresentados os princípios e padrões para o desenvolvimento de sistemas de larga escala e os desafios no desenvolvimento de aplicações. Engenharia de software e pensamento computacional A engenharia de software teve início em meados da década de 1960, após longos anos de hegemonia do hardware. Nas décadas que antecederam, grandes máquinas eram utilizadas para a validação de problemas científicos em universidades, algumas grandes empresas ou agências governamentais. O software não era relevante e essas grandes máquinas tinham pouco poder de processamento equiparado aos atuais computadores domésticos. Ainda assim, podiam calcular milhares de vezes mais rápido do que os melhores matemáticos do mundo (DENNING; TEDRE, 2019). Pouco tempo depois, calcular não era mais suficiente, de modo que di- ferentes aplicações começaram a surgir. De simuladores que desafiavam enxadristas até a implantação dos primeiros sistemas projetados para os hospitais norte-americanos (DENNING; TEDRE, 2019; ARREGUY-SENA, 1999), o software foi inserido em diversas áreas de conhecimento com a intenção de dar suporte à tomada de decisão, à pesquisa e ao lazer. Portanto, a aurora da computação moderna teve início com o hardware, mas o software logo ganhou território (DENNING; TEDRE, 2019). Por consequência do aumento da demanda, a escala e a complexidade desses novos sistemas também sofreram impacto importante, ainda em um momento em que os processos de desenvolvimento eram relativamente imaturos. Garantir a qualidade da produção em grande escala (confiabilidade, usabilidade, segurança, entre outras características) era inviável, pois as ferramentas para desenvolvimento e gestão desenvolvidas até então não eram poderosas o suficiente para isso. Tal cenário levou ao aumento da Pensamento computacional para sistemas de larga escala2 descrença no software, devido a recorrentes perdas de prazo, orçamento elevado, falta de atendimento aos requisitos e manutenção inviável. De acordo com Valente (2020), a apreensão era tanta que esse período foi chamado de “crise do software”. Tanta era a preocupação que,em 1968 e 1969, a Organização do Tratado do Atlântico Norte (OTAN) patrocinou duas reuniões para debater o assunto. O objetivo era discutir um problema crescente na computação, o software. Casos catastróficos, como o caso do lançamento da Mariner I, uma sonda interplanetária produzida pela National Aeronautics and Space Administration (NASA) destinada a fazer pesquisas aéreas de Marte, Mercúrio e Vênus e que perdeu o controle 293 segundos após a decolagem em virtude de um erro de programação mínimo (DENNING; TEDRE, 2019), reforçaram a importância da discussão. A conferência, ocorrida na cidade de Garmisch (Alemanha), reuniu pes- quisadores em busca de uma solução para a crise que havia se instaurado. Era consenso a necessidade que fosse definido com urgência um conjunto de princípios teóricos e práticos, um arcabouço de regras que direcionasse a construção de software consistentes e confiáveis. Assim, eles buscaram nas engenharias, área de conhecimento reconhecida em notáveis processos de construção em todas as subáreas que atuam, inspiração para essa nova área computacional, então batizada de engenharia de software. Mais de meio século após sua criação, a aplicação do pensamento compu- tacional aliado à rigidez formal da engenharia trouxe avanços em metodologias e técnicas de desenvolvimento consideravelmente notáveis. Princípios e padrões foram definidos e aplicados em sistemas de grande escala, de forma que favorecem a reutilização e a redução de tempo de produção. Frameworks e bibliotecas agilizam o trabalho, de forma que os desenvolvedores podem abstrair detalhes inerentes a processos comuns, como interfaces, bases e estruturas de dados, criptografia, etc. Também metodologias para teste e validação são utilizadas para garantir qualidade e eliminação de falhas, bem como para a manutenção e a evolução durante o passar do tempo. Pensamento computacional em sistemas de larga escala Como vimos anteriormente, desde sua origem, no interior das universidades, o pensamento computacional do início da era do computador era rico, mas fragmentado, e focava em fazer programas individuais funcionarem em má- quinas específicas (DENNING; TEDRE, 2019). Muitos desses sistemas, como já Pensamento computacional para sistemas de larga escala 3 foi mencionado, eram relativamente pequenos comparados às aplicações dos dias atuais. E não estamos falando de grandes sistemas de informação: um aplicativo embarcado em seu celular já possui capacidade computacional superior à disponível naquela época. Grande parte daqueles programas era direcionada para a resolução de cálculos matemáticos complexos, que exigiam grande esforço dos matemáticos de então. Atualmente, diversos segmentos têm empregado esforços para a cons- trução de sistemas cada vez mais complexos e escaláveis, com inserção em diversas áreas do conhecimento, como ciência, pesquisa, gestão governa- mental, esportes, medicina, entre outros ramos. Diferentemente dos primeiros anos do computador, quando o hardware reinava absoluto, com o passar do tempo, a demanda por software aumentou exponencialmente. Sistemas ampliaram sua escala de forma considerável, de modo que os sistemas, antes individuais e para uso específico, tornaram-se complexos, multitarefas e essenciais. Como exemplos, podemos citar o con- trole de processos produtivos na indústria, em logística, na forma de controle de frota, em sistemas governamentais (eleições, impostos e serviços), nos negócios digitais, agindo de forma ubíqua, na forma de serviços baseados em perfis de comportamento dos consumidores, etc. Uma ampla variedade de sistemas também está embarcada em diversos equipamentos, como automó- veis, aeronaves, satélites, usinas nucleares, etc. O pensamento computacional e a evolução das técnicas de construção de software proporcionaram solo fértil para pesquisas e descobertas recentes e para as que ainda estão por vir. O termo computação ubíqua foi cunhado em 1991, por Mark Weiser, no artigo “O Computador para o século XXI”, no qual apresentava o conceito de dispositivos conectados em todos os lugares de forma imperceptível para o ser humano, de forma que acabaríamos por não notar sua influência em nosso cotidiano. Seu objetivo é oferecer serviços de forma “invisível”, de modo que os serviços são oferecidos e utilizados sem mesmo percebermos, baseado em perfis de comportamento do usuário e sua rotina. Para isso, um perfil é criado utilizando as mais diversas fontes, como o aparelho celular (áudio, aplicativos, etc.), ou outras formas de acesso (smart TV, computador pessoal e dados de redes Wi-Fi públicas, etc.), criando o conceito de computação sensível ao contexto, ou seja, ajustando o serviço que é oferecido à situação e ao local onde o usuário se encontra. Por exemplo, oferecer um cupom de desconto para determinado produto ao identificar que o usuário está passando em frente à loja. Pensamento computacional para sistemas de larga escala4 Mas o que mudou do momento que passamos das simples aplicações monotarefas para sistemas de complexos e multiusuários? Os pesquisado- res e profissionais da computação também tiveram que se adaptar, visto que as habilidades e competências antes exigidas para um programa que não passava de mil linhas de codificação agora são outras, considerando construir um software com mais de um milhão de linhas (RILEY; HUNT, 2014). O trabalho antes realizado por um único programador agora exige trabalho em equipe. Os profissionais, antes solitários e escondidos nos datacenters, com o passar do tempo precisaram aprender a organizar e gerenciar equipes e a desenvolver metodologias para o desenvolvimento de software bem-sucedido (DENNING; TEDRE, 2019). E essa não é uma tarefa simples. Brooks (1986), um dos pesquisadores que definiu regras básicas de pensamento computacional, seguidas até hoje, concluiu que gerenciar a equipe é um desafio maior do que os problemas de tecnologia que a equipe precisará resolver. Outro ponto de aprendizado é que existiria a necessidade de ferramentas próprias, diferentes das tradicionais, devido a diferenças essenciais entre software complexos e grandes sistemas físicos, como pontes, edifícios, aviões e navios: um erro em um único bit de código pode causar falha catastrófica, enquanto a perda de uma pequena lasca de material pode até desgastar a construção, mas dificilmente vai causar um colapso na estrutura (VALENTE, 2020). Fez-se necessária, então, a definição de princípios e padrões próprios, que poderiam ser utilizados por engenheiros de software ou desenvolvedores em suas construções, de forma que eles aproveitassem experiências bem- -sucedidas e evitassem recomeços a cada novo problema de projeto. Princípios e padrões para a engenharia de software No primeiro momento, quando se fala em engenharia de software, logo se pensa em programação, mas a área de estudo envolve um universo mais amplo. Além das técnicas de programação, a engenharia de software se concentra em recomendar princípios e padrões da engenharia na construção de software, utilizando pensamento computacional e processos sistêmicos, de maneira disciplinada e quantificável, com a finalidade de construir, manter e evoluir sistemas de software. Software, portanto, não é apenas o arquivo executável final, pois inclui toda a documentação necessária (arquivos de configuração, manual de instalação e utilização) e o banco de dados. Pensamento computacional para sistemas de larga escala 5 Para essa área de concentração, software consiste em uma coleção de requisitos, tanto não funcionais quanto funcionais, que atendam às necessi- dades do cliente. No modelo do processo de desenvolvimento de software, o projeto é o primeiro estágio no processo de construção de software. Faz a ligação entre o projeto e a engenharia de requisitos, pois identifica os prin- cipais componentes estruturais de um sistema e os relacionamentos entre eles (SOMMERVILLE, 2007). O pensamento computacionalsugere soluções, como realizar a decom- posição do problema, para que cada segmento do projeto seja implemen- tado independentemente, e o uso de abstrações para criar representações simplificadas das entidades, reduzindo sua complexidade. Tais abstrações permitem interagir e utilizar a entidade abstraída, reduzindo a necessidade de dominar todas as minúcias envolvidas em sua implementação. São arte- fatos oferecidos pelas linguagens de programação com os quais podemos representar as abstrações, como, por exemplo, métodos, classes, pacotes, pacotes, interfaces, bibliotecas, etc. Porém, reduzir a complexidade do projeto não é um tema simples, con- siderando que os sistemas modernos aumentam cada vez mais sua comple- xidade. Segundo Wirth (2008), isso afeta a qualidade do produto e, muitas vezes, problemas de projeto são disfarçados pelo hardware, com o uso de processadores mais rápidos ou deficiências no design de dados ocultos pelo uso de dispositivos de armazenamento maiores. Um projeto bom e cuidadoso consome tempo e pode ter custo elevado, mas ainda é mais barato do que um software sem usabilidade e não confiável, levando em conta o custo de “manutenção” (WIRTH, 2008). Pensando em incremento na qualidade, capacidade de identificar e pro- jetar integrações com outros sistemas e recursos, expansões e possíveis incrementos de escala, é interessante conhecer e aplicar algumas práticas do pensamento computacional. Vejamos. � Princípios de projeto: descrições de habilidades e estratégias que os desenvolvedores seguem ao tomar decisões de design. � Padrões de projeto: descrições de situações comuns que um progra- mador provavelmente encontrará. Eles oferecem orientação sobre como estruturar o programa ou sobre o processo de escrevê-lo, para obter melhores resultados. Pensamento computacional para sistemas de larga escala6 Tanto os princípios quanto os padrões podem ser compreendidos como um conjunto de regras práticas ou de conselhos, mais úteis para aqueles com habilidades avançadas no desenvolvimento de sistemas. Aprender suas principais ferramentas e habilidades exige uma certa dose de atenção, per- sistência e disciplina, e, como a maioria das competências que o ser humano desenvolve, também demanda bastante prática. Princípios Em termos gerais, princípios são conceitos ou valores que orientam a tomada de decisão. Assim, os princípios de projeto são recomendações concretas que desenvolvedores de software podem incorporar à forma de raciocínio e aos hábitos que os desenvolvedores de sistemas desenvolvem ao longo do tempo, ao construir sistemas de computação complexos (DENNING; TEDRE, 2019). Eles representam diretrizes para garantir que um projeto atenda a determinadas propriedades e se aplicam a qualquer sistema de larga escala capaz de gerenciar grandes volumes de usuários e processos concomitan- tes. Como exemplos práticos, podemos destacar os Princípios de Saltzer e Schroeder (1975) para proteção de informações e os princípios SOLID. Por sua extensão e complexidade, vamos conhecer resumidamente alguns conceitos sobre esses princípios. Para auxiliar sua leitura, muitos dos princípios e padrões são voltados para o paradigma orientado a objetos. Sem estender os conceitos, abaixo são descritos alguns dos termos recorrentes em orientação a objetos e que não foram tratados diretamente no capítulo. � Classe abstrata: normalmente é formada por métodos abstratos. O método abstrato descreve somente a assinatura do método e, portanto, não con- tém código interno (implementação do método). Esses métodos são imple- mentados em suas classes derivadas concretas, em que são definidos seus comportamentos específicos. � Classe concreta: possui atributos, métodos construtores e demais componen- tes necessários, e pode ser instanciada, ou seja, permite a criação de objetos a partir dela. Classes concretas podem ser herdadas por outras classes. � Interface: utilizada para a definição de um modelo por meio da assinatura de métodos. Assim como na classe abstrata, a implementação desse método será realizada pelas classes que a herdarem. O uso de interfaces possibilita o polimorfismo. Pensamento computacional para sistemas de larga escala 7 � Acoplamento: é a medida de quanto dois ou mais módulos estão “amarrados”, ou seja, de quanto uma classe depende da outra para efetuar seu trabalho. O ideal é buscar o mais baixo acoplamento, em que cada uma depende de si mesma para executar as tarefas. Alto acoplamento existe, por exemplo, quando parte de um processo está em uma classe (ou módulo) e o restante está em outra (nenhuma das duas consegue entregar o resultado sozinha). � Coesão: um módulo coeso realiza uma única tarefa dentro de um procedimento de software, requerendo pouca ou nenhuma interação com procedimentos sendo realizados em outras partes de um programa. Uma classe não deve assumir responsabilidades que não são suas (Princípio da Responsabilidade Única). Segundo Saltzer e Schroeder (1975), em um projeto de software, para ga- rantir qualidade no quesito segurança da aplicação, o desenvolvedor deve ter em mente oito princípios fundamentais, de forma a evitar possíveis compro- metimentos de informações confidenciais. Esses princípios são os seguintes. 1. Economia de mecanismos: o primeiro princípio diz respeito aos algo- ritmos e métodos empregados na implementação da segurança, aqui chamados de mecanismos. Esses mecanismos devem ser, na medida do possível, simples e sucintos no tocante à codificação, facilitando sua leitura e minimizando a possibilidade de erros de codificação. 2. Bloquear acessos por padrão: sistemas devem, naturalmente, negar acessos a seus recursos, com a exceção de que o acesso tenha sido concedido de forma explícita. As funcionalidades de um sistema só poderão ser executadas se tiverem permissão para tal. Por exemplo, um sistema só deve receber acesso à internet permitido no momento de aplicar uma atualização. 3. Mediação completa: qualquer acesso solicitado, mesmo para recursos do sistema operacional, deve ser verificado (mediação). Dessa forma, para cada solicitação, aproveita-se para verificar se existe autorização para tal acesso. 4. Padrão aberto: a segurança do sistema não deve depender da ignorância dos invasores sobre como é construída sua aplicação. O sistema deve se respaldar em mecanismos de segurança, como senhas e encriptação por chaves, e não em esconder a arquitetura ou os componentes utilizados. 5. Separação de privilégios: evite criar perfis que tenham grandes níveis de acesso. Tente separar as ações de forma a gerenciar permissões somente das partes necessárias a cada atividade. Pensamento computacional para sistemas de larga escala8 6. Menor privilégio: apenas permissões estritamente necessárias devem ser consentidas, e cada perfil deve ter as permissões necessárias para executar sua tarefa, nada mais. 7. Menor número de mecanismos comuns (compartilhados): deve-se evitar o compartilhamento de recursos para evitar acessos indesejados. Um mecanismo (recurso) comum contém informação vinculada e, caso alguém o acesse, pode tentar influenciar no comportamento de outros que dependem dele. Por exemplo, uma base de dados de usuários utilizada para autenticação por diversas aplicações. Uma solução seria cada sistema ter sua própria base para controle de acessos, mesmo com informações replicadas, o que pode incrementar a segurança. 8. Aceitação psicológica: princípio também conhecido como psicologi- camente aceitável, diz que as regras devem ser razoáveis, pois, se a interação com o usuário não for intuitiva, o mecanismo de segurança até pode ser eficaz, mas tende a falhar porque não será utilizado da maneira correta e seguido com o rigor esperado. Outro conjunto de princípios de destaque na engenharia de software é o que resultou do trabalho de Robert Martin, em um artigo chamado de “Principles of Object Oriented Design” e expandido em outras publicações (MARTIN;NEWKIRK; KOSS, 2003), os Princípios SOLID. Eles compreendem cinco técnicas de programação orientada a objetos que facilitam o desenvolvimento de software, tornando-o mais compreensível, flexível e de fácil manutenção. O acrônimo SOLID é formado pela letra inicial de cada uma das técnicas. Veja um resumo no Quadro 1. Quadro 1. Resumo dos conceitos SOLID Letra Sigla Nome Definição S SRP Princípio da Responsa- bilidade Única (Single Responsibility Principle) Uma classe deve ter uma, e somente uma, razão para mudar. O OCP Princípio Aberto-Fechado (Open Closed Principle) Você deve ser capaz de es- tender um comportamento de uma classe sem precisar modificá-la. L LSP Princípio da Substituição de Liskov (Liskov Substitu- tion Principle) As classes-base devem ser substituíveis por suas classes derivadas. (Continua) Pensamento computacional para sistemas de larga escala 9 Letra Sigla Nome Definição I ISP Princípio da Segregação da Interface (Interface Segre- gation Principle) Interfaces específicas são melhores do que uma interface geral. D DIP Princípio da inversão da dependência (Dependency Inversion Principle) Dependa de abstrações, não de implementações. Fonte: Adaptado de Martin, Newkirk e Koss (2003). Os princípios SOLID são fortemente ligados ao paradigma de orientação a objetos e suas técnicas são voltadas para a escrita de código padronizada, de forma que seja mais simples aumentar a escala do sistema ou realizar manutenções. Veja, abaixo, uma descrição mais aprofundada sobre os cinco princípios SOLID. � Princípio da Responsabilidade Única: cada classe (também aplicável a métodos) implementada no sistema deve possuir somente uma respon- sabilidade (MARTIN; NEWKIRK; KOSS, 2003). Considere responsabilidade como qualquer ação atribuída para a classe; assim, para estar de acordo com o princípio, a classe não deve ter responsabilidades fora do seu contexto. Ela deve possuir um único tipo de tarefa. Por exemplo, uma classe responsável pelo cadastro de usuários no sistema deve conter apenas funcionalidades para cadastro. Caso ela necessite enviar um e-mail de confirmação para completar o cadastro, essa função deve estar em outra classe, especializada em enviar e-mails. Deve-se separar cada funcionalidade em classes, mesmo que se pareça estar sobrecar- regando o sistema com diversas classes. Por outro lado, cada classe será mais simples de compreender e sua manutenção será facilitada. � Princípio do Aberto/Fechado: sua formalização afirma que objetos ou entidades devem estar abertos (disponíveis) para extensão, mas fechados para receber modificações. Ou seja, você deve ser capaz de realizar herança de comportamentos de outra classe, mas não deve reescrever seu código original (MARTIN; NEWKIRK; KOSS, 2003). Para isso, segundo Martin, Newkirk e Koss (2003), você deve separar qualquer funcionalidade que possa ser estendida em uma estrutura chamada de interface, depois inverter as dependências. Na prática, deve-se optar (Continuação) Pensamento computacional para sistemas de larga escala10 por interfaces e, se elas estiverem bem definidas, os sistemas estarão abertos para extensão. � Princípio da Substituição de Liskov: segundo Martin, Newkirk e Koss (2003), uma classe derivada deve ser substituível por sua classe-base, ou seja, todas as classes que herdam um método (classe filha ou derivada) de uma classe pai não devem repetir a funcionalidade já implementada nessa classe pai (a classe-base). Seguindo esse conceito, a classe pai deve poder ser substituída por qualquer uma de suas subclasses em qualquer região do código. Esse princípio permite aplicar o polimorfismo de forma mais segura. Com ele, podemos utilizar métodos de classes filhas implementando a classe pai sem preocupações com resultados inesperados. Geralmente utilizamos esse princípio associado a outros, como o Aberto/Fechado e a Segregação de Interface. � Princípio da Segregação de Interface: uma classe não deve ser com- pelida a implementar interfaces e funcionalidades que não serão uti- lizadas. Resumindo, é melhor criar várias interfaces específicas do que somente uma interface genérica (MARTIN; NEWKIRK; KOSS, 2003). � Princípio de Inversão de Dependência: caso seja necessário criar alguma dependência, evite que componentes de alto nível dependam de com- ponentes de baixo nível. Ou seja, um componente mais especializado não deve depender de um componente menos especializado. Caso seja necessário, deve-se criar uma classe abstrata com as funcionalidades e fazê-las depender da abstração. O Princípio da Inversão de Dependência é um princípio essencial para um bom design orientado a objetos, ao passo que o oposto leva ao aumento do acoplamento entre os módulos. Esses conceitos podem ser aplicados a qualquer linguagem de progra- mação orientada a objetos (Java, por exemplo) e, embora pareça um pouco complicado no início, quando aprendidos e implementados corretamente, ajudam os desenvolvedores a criar aplicações de larga escala que permitem extensões, modificações, testes e refatoração com dificuldade reduzida. Padrões Em meados da década de 1970, um engenheiro civil chamado Cristopher Alexander percebeu que as construções da época seguiam, da menor a mais sofisticada, padrões bem semelhantes. Para cada tipo de estrutura, os proble- mas eram sempre os mesmos, e as soluções aplicadas eram muito parecidas. Então, ele catalogou os problemas observados e descreveu as soluções para Pensamento computacional para sistemas de larga escala 11 cada caso. Assim, foi publicada The Timeless Way of Building (ALEXANDER, 1979), considerada como a primeira bíblia da engenharia civil, que tratava exatamente de padrões para construção na área da engenharia civil. Com o mesmo objetivo, descrever um problema que ocorre repetidamente e um conjunto reutilizável de soluções para esse problema, em 1995, os auto- res Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides publicaram o livro Design patterns: elements of reusable object-oriented software (GAMMA et al., 1995), traduzido pela Editora Bookman em 2000, catalogando mais de 20 padrões de solução de problemas e suas aplicações. O livro lhes rendeu o apelido de “Gangue dos Quatro” (Gang of Four, ou GoF) e ainda hoje é referência para desenvolvimento orientado a objetos. Um padrão de software caracteriza muitas situações que um progra- mador provavelmente encontrará e oferece orientação sobre como estruturar o programa para melhor se ajustar ao padrão. Mas não confunda padrão de projeto com reaproveitamento de código, pois padrões de projeto não estão ligados somente à codificação. Em vez de pensar somente em reutilização de código, com padrões você tem reutilização de experiência! Segundo o catálogo do GoF (GAMMA et al., 1995), os padrões são divididos em três categorias: de criação, estrutural e comportamental. Mas antes de falar das categorias, é importante comentar que os padrões de objeto, além das categorias, podem ser classificados também em relação a seu escopo: de classe ou de objetos. Padrões com escopo de classe vão utilizar a herança para compor ou variar os objetos, mantendo a flexibilidade do sistema. Já os padrões de objeto vão delegar suas responsabilidades para um objeto. � Criação: os padrões de criação são aqueles que criam objetos para você, em vez de instanciar objetos diretamente. Isso dá, a seu programa, mais flexibilidade para decidir quais objetos precisam ser criados para determinado caso. � Estrutural: os padrões estruturais são aqueles relacionados à com- posição de classes e de objetos. Eles usam herança para compor in- terfaces e definem maneiras de construir objetos para obter novas funcionalidades. Pensamento computacional para sistemas de larga escala12 � Comportamental: a maioria desses padrões de design está especifi- camente relacionada à comunicação entre objetos. No Quadro 2, são apresentados todos os padrões descritos no livro, cada umjá categorizado conforme seu escopo e propósito. Note que a maioria dos nomes é intuitiva, facilitando sua identificação e aplicação. Quadro 2. Classificação dos padrões segundo GoF Propósito Criação Estruturais Comportamentais Es co po Cl as se Factory Method Adapter (class) Interpreter Template Method O bj et o Abstract Factory Builder Prototype Singleton Adapter (object) Bridge Composite Decorator Façade Flyweight Proxy Chain of Responsibility Command Iterator Mediator Memento Observer State Strategy Visitor Fonte: Adaptado de Gamma et al. (1995). Agora falando especificamente de cada um dos padrões de projeto (ou design patterns), eles descrevem uma solução geral e reutilizável para um problema frequente no desenvolvimento de sistemas orientados a objetos. Um padrão não se trata de modelos ou classes prontas para uso, mas de descrições de como resolver o problema do qual ele trata, que pode ser usado (e até adaptado) em muitas situações diferentes. Eles não são ligados somente à codificação, mas também a formas de solucionar questões de desenvolvimento com base em soluções com eficácia comprovada. Em vez de pensar somente em reutilização de código, com padrões você tem reutilização de experiência de outros desenvolvedores. Pensamento computacional para sistemas de larga escala 13 Cada padrão de projeto apresenta os mesmos itens básicos e, estrutural- mente, segue a mesma disposição: � Nome � Problema ■ Quando aplicar o padrão. � Solução ■ Descrição que comunica o problema e como usar classes e objetos para o resolver. � Consequências � Custo-benefício de usar o padrão ■ Impactos no sistema (flexibilidade, extensibilidade, portabilidade e eficiência do sistema). Em Gamma et al. (1995), cada padrão é extensamente detalhado, incluindo situações de uso, exemplos de codificação, cenários, etc. Como exemplo, abaixo é apresentado resumidamente o padrão estrutural Adapter. O padrão estrutural Adapter converte a interface de uma classe em outra interface que o cliente espera. Assim, permite que classes que normalmente não poderiam trabalhar juntas, devido à incompatibilidade de interfaces, possam fazê-lo. Em outras palavras, imagine que você necessita ligar um plugue de pinos chatos em uma tomada com três furos usando um adaptador de tomada. O padrão Adapter utiliza o mesmo conceito, criando uma forma para que as duas interfaces possam se comunicar. Use o Adapter quando: � você quer usar uma classe existente, mas sua interface não é adequada àquela que você precisa; � você quer criar uma classe reusável que coopera com classes não relaciona- das ou não previstas, isto é, classes que não necessariamente têm interfaces compatíveis; � você precisa usar várias subclasses existentes, mas é impraticável adaptar suas interfaces especializando cada uma. Um object adapter pode adaptar a interface de suas classes pai. Atualmente, diversas linguagens e Frameworks incorporaram alguns desses padrões. O Dot Net da Microsoft, por exemplo, tem disponível o componente de acesso a dados ADO.net, que utiliza os padrões Adapter e Command. Pensamento computacional para sistemas de larga escala14 Outro exemplo de padrão para construção é o padrão GRASP (abreviatura de General Responsibility Assignment Software Patterns), livremente traduzido como Padrões de Software Atribuídos à Responsabilidade Geral (LARMAN, 2006), que descreve princípios fundamentais de atribuição de responsabili- dade a objetos e são recomendações para melhor documentar e padronizar princípios antigos e exaustivamente testados de design orientado a objetos. Os diferentes patterns e princípios usados em GRASP são detalhados abaixo. � Controller (controlador): encarrega a responsabilidade de lidar com os eventos do sistema a uma classe de interface gráfica (utilizado no MVC [model-view-controller]). � Creator (criador): incumbido da criação de objetos a partir de classes (similar ao Factory do GoF). � Indirection (indireção): reduz o acoplamento entre componentes de software atribuindo a mediação da relação entre os dois a uma terceira classe (usado no MVC). � Information Expert (especialista): utilizado para distribuir as respon- sabilidades entre as classes, sejam métodos, atributos, etc. � High Cohesion (alta coesão): padrão que tenta conservar os objetos gerenciáveis, focados e compreensíveis. � Low Coupling (baixo acoplamento): para diminuir a dependência entre as classes, diminuir o impacto que as alterações em uma causam nas outras e aumentar o potencial de reúso das classes. � Polymorphism (polimorfismo): a responsabilidade de estabelecer variações de comportamentos baseada no tipo é imputada aos tipos para os quais essa variação é verificada. � Protected Variations (variáveis protegidas): resguarda um componente das variações ocorridas em outros componentes. Para isso, o foco da instabilidade é encapsulado por uma interface, utilizando polimorfismo para criar as implementações dessa interface. � Pure Fabrication (fabricação própria): classes artificiais especialmente criadas para alcançar baixo acoplamento, alta coesão e potencial reuso. Não representam qualquer conceito do domínio do problema. Além do GoF e do GRASP, outros tantos padrões podem ser empregados, como padrões J2EE da Sun, os padrões JSP, padrões arquiteturais, padrões de projetos de jogos, etc. Pensamento computacional para sistemas de larga escala 15 Dificuldades no desenvolvimento de aplicações reais A produção de um software guarda muitas diferenças em comparação com as produções de outras engenharias, sobretudo se compararmos o avanço do hardware ao do software. Brooks (1986), em ensaio denominado “No Silver Bullet” (traduzindo, “Sem bala de prata”), descreveu suas observações e teceu uma análise sobre as particularidades da área baseado no contexto da época. Ele dividiu os problemas na produção de software em duas categorias: acidentais e essenciais. Os problemas acidentais estão ligados principalmente a limitações tecnológicas, enquanto os problemas essenciais estão ligados à natureza do software, de modo que improvavelmente algum dia poderão ser superados por qualquer inovação tecnológica ou metodologia criada. Os problemas acidentais, como estão ligados a dificuldades tecnológicas, são mais simples de resolver caso o profissional esteja devidamente capa- citado e tenha acesso aos devidos recursos e tecnologias. As dificuldades acidentais foram reduzidas graças ao aprimoramento de tecnologias, como linguagens de alto nível, e avanços em hardware e em sistemas operacionais (DENNING; TEDRE, 2019). As dificuldades essenciais, segundo Brooks (1986), são naturalmente ge- radas pela característica abstrata do software. Tal particularidade o torna intangível e complexo de estimar, dificultando qualquer estimativa de esca- labilidade ou esforço para construção. Outro problema essencial se deve a suas naturais complexidade e irredutibilidade, o que torna impossível de ser simplificado sem que ocorra perda significativa de informação (BROOKS, 1986). No mesmo artigo, Brooks (1986) apresenta quatro características que afetam o processo de desenvolvimento de software e tornam sua construção essencialmente complexa. Vejamos. 1. Complexidade: muitos dos problemas do software são derivados de sua complexidade quanto ao crescimento não linear. Ampliar a escala de um sistema não consiste em alterar o tamanho de suas partes, como é feito com qualquer outra construção física, como componentes de hardware, cuja escala pode ser variada aumentando ou reduzindo o tamanho de seus componentes. 2. Conformidade: software precisa se adaptar ao contexto, que pode mudar a qualquer momento. Por exemplo, caso uma legislação traba- lhista seja alterada, espera-se que sistemas relacionados a esse tipo de legislação se adaptem rapidamente. Pensamento computacional para sistemas de larga escala16 3. Mutabilidade: quando um produto físico fica obsoleto, porexemplo, geralmente é substituído por um modelo atualizado, considerando que os custos e a complexidade para reconstrução do produto não compensariam o esforço. Devido a sua natureza intangível, o software está sempre sofrendo mudanças. Outrossim, boa parte das vezes, são solicitadas mudanças que ultrapassam seus limites originais. 4. Invisibilidade: por ser um bem imaterial e de natureza abstrata, um software não pode ser demonstrado visualmente. Por mais conheci- mento que possuam, nem usuário, nem programador conseguem ter uma visão completa do software, pois geralmente um lado não com- preende todas as questões tecnológicas e o outro desconhece todas as regras de negócio envolvidas, ainda mais se o desenvolvimento for em equipe, quando o conhecimento é mais distribuído ainda. A falta de visão do todo acarreta o aumento da probabilidade de que erros na construção ocorram. Essas dificuldades são inerentes ao software, de forma que algumas delas podem nunca ocorrer em outras áreas da engenharia. Utilizemos como exemplo a construção de um objeto doméstico relativamente comum, uma geladeira, para comparar com as dificuldades essenciais definidas por Brooks (1986). � Caso o fabricante queira produzir geladeiras com tamanhos diferentes, é possível mudar a escala das peças e produzir um equipamento maior, o que, como vimos, não é viável do caso de software. � A construção de uma geladeira segue normas e legislações específicas; porém, quando elas são alteradas, os fabricantes têm anos para se adaptar (ou se conformar) às novas leis, diferentemente do que ocorre com software. � As geladeiras dificilmente ganham novas funcionalidades, sobretudo depois que foram vendidas. Até onde se tem conhecimento, nenhum fabricante resolve adicionar portas depois que o produto está na linha de montagem ou mesmo em um produto que já está na posse do cliente final. Com software, porém, essa mutabilidade é possível. � Finalmente, a geladeira é um objeto com peso, altura, volume interno, etc., que gera base para precificação e comparação pelos consumidores finais, o que não acontece com software. Pensamento computacional para sistemas de larga escala 17 Perceba que as características particulares de cada engenharia podem não ser afetadas pelas dificuldades essenciais; ao mesmo tempo, elas podem ter impactos consideráveis no desenvolvimento do software e estão ligadas, principalmente, à capacidade do ser humano de compreender a essência de problemas complexos. Essas dificuldades essenciais são tão significativas que receberam uma analogia interessante, que inclusive dá o título ao artigo mencionado. A menção a “bala de prata” é uma analogia às tentativas de encontrar uma solução para o problema do software. O autor faz uma comparação entre a lenda do licantropo (lobisomem da cultura popular) com o problema da complexidade do software. Em relação ao ser sobrenatural, basta uma única bala de prata para que seja possível salvar o dia, ao contrário dos problemas que envolvem a produção de software, pois, considerando as dificuldades essenciais, inexiste uma solução única, a “bala de prata”. Atualmente, essas dificuldades enfrentadas pela engenharia de software estão cada vez mais amplificadas com o advento de novas tecnologias e necessidades. Denning e Tedre (2019) elencam alguns desses novos desafios. Vejamos. � Intrusões e malwares: quanto mais escalares os sistemas, mais com- plexo é garantir a ausência de vulnerabilidades. Criminosos virtuais estão sempre buscando brechas que possam ser exploradas; Tais aces- sos indevidos podem não só comprometer severamente a privacidade do proprietário, como também podem danificar a máquina infectada; � Tolerância a falhas: a complexidade inerente ao software e sua de- pendência do hardware causa impactos na garantia de que o sistema se recupere adequadamente mesmo após a ocorrência de falhas em alguns componentes. Caso isso ocorra, a qualidade do serviço é reduzida proporcionalmente à severidade da falha. � Hardware seguro: tentativas de explorar vulnerabilidade também ocorrem em nível de hardware, direcionadas às camadas mais baixas do núcleo e à rede, explorando a incapacidade de manutenção de monitoramento eficiente. Atualmente, com a intensificação do uso de tecnologias baseadas em IoT (Internet of Things, ou Internet das Coisas), preocupações com a segurança em nível de hardware voltaram à discussão. � Algoritmos de machine learning: uma preocupação recorrente com machine learning (aprendizado de máquina, em tradução para o por- tuguês) são as falhas decorrentes de erros em seu treinamento. Como Pensamento computacional para sistemas de larga escala18 saber se as situações que foram descartadas do treinamento não são justamente os pontos de possíveis falhas? A complexidade em tentar responder aumenta conforme novas camadas de neurônios são adi- cionadas a uma intrincada sequência de conexões. � Segurança: sistemas críticos estão inseridos em diversos ambientes: monitores cardíacos, controladores de temperatura em usinas ter- monucleares, equipamentos de voo em uma aeronave comercial, etc. Falhas em qualquer desses cenários podem ser catastróficas, tanto em âmbito patrimonial quanto para a vida. � Produção em massa de diversos produtos de software: com a crescente procura por aplicativos em geral, sua produção também deve ser am- pliada e acelerada, muitas vezes incluindo módulos ou funcionalidades de terceiros para agilizar a conclusão e atender à demanda. Nem sempre o desenvolvedor avalia a implementação das dependências de sua aplicação, levando complexidade ou mesmo riscos de segurança para sua construção. Perceba que as características particulares de cada engenharia podem não ser afetadas pelas dificuldades essenciais. Ao mesmo tempo, elas po- dem impactar consideravelmente o desenvolvimento do software e estão ligadas, sobretudo, à capacidade do ser humano de compreender a essência de problemas complexos. Transcorridos mais de 50 anos da histórica Conferência da OTAN, é notável a quantidade de avanços desenvolvidos, de novas metodologias e técnicas para a construção de software. O pensamento computacional precisa ser desafiado constantemente a continuar se desenvolvendo, auxiliando, desse modo, na criação de novos recursos conforme os avanços tecnológicos con- tinuam apresentando novos desafios. Referências ALEXANDER, C. The timeless way of building. Oxford: Oxford University Press, 1979. ARREGUY-SENA, C. Proposta de fluxo de dados no projeto de informatização do hospital- -dia para infectados pelo HIV em Juiz de Fora – MG. Revista Mineira de Enfermagem, v. 3, nº 1, p. 46–53, 1999. BROOKS JR., F. P. No silver bullet: essence and accidents of software engineering. IEEE Computer, v. 20, nº 4, p. 10–19, 1986. Disponível em: http://worrydream.com/refs/ Brooks-NoSilverBullet.pdf. Acesso em: 29 dez. 2020. DENNING, P. J.; TEDRE, M. Computational thinking. Cambridge: MIT Press, 2019. Pensamento computacional para sistemas de larga escala 19 GAMMA, E. et al. Design patterns: elements of reusable object-oriented software. Boston: Addison-Wesley, 1995. LARMAN, C. Utilizando UML e padrões: uma introdução à análise e ao projeto orientados a objetos e ao desenvolvimento iterativo. 3. ed. Porto Alegre: Bookman, 2006. MARTIN, R. C.; NEWKIRK, J. W.; KOSS, R. S. Agile software development: principles, patterns, and practices. Upper Saddle River: Pearson, 2002. RILEY, D.; HUNT, K. A. Computational thinking for the modern problem solver. Boca Raton: CRC Press, 2014. SALTZER, J. H.; SCHROEDER, M. D. The protection of information in computer systems. Proceedings of IEEE, v. 63, nº 9, p. 1278–1308, 1975. Disponível em: http://web.mit.edu/ Saltzer/www/publications/protection/. Acesso em: 29 dez. 2020. SOMMERVILLE, I. Engenharia de software. 8. ed. São Paulo: Person, 2007. VALENTE, M. T. Engenharia de software moderna: princípios e práticas para desenvol- vimento de softwarecom produtividade. Belo Horizonte: Marco Tulio Valente, 2020. WIRTH, N. A brief history of software engineering. IEEE Annals of the History of Com- puting, v. 30, nº 3, p. 32–39, 2008. Leituras recomendadas BEECHER, K. Computational thinking: a beginner's guide to problem-solving and pro- gramming. Swindon: BCS, 2017. GAMMA, E. et al. Padrões de projeto: soluções reutilizáveis de software orientado a objetos. Porto Alegre: Bookman, 2000. Os links para sites da web fornecidos neste capítulo foram todos testados, e seu funcionamento foi comprovado no momento da publicação do material. No entanto, a rede é extremamente dinâmica; suas páginas estão constantemente mudando de local e conteúdo. Assim, os edito- res declaram não ter qualquer responsabilidade sobre qualidade, precisão ou integralidade das informações referidas em tais links. Pensamento computacional para sistemas de larga escala20 Dica do professor Ao iniciar um projeto, o desejo de construir o melhor código possível, de prever necessidades antes mesmo que elas ocorram ou de reduzir o tempo de entrega do projeto pode vir a criar grandes desafios, podendo causar impactos negativos no momento de expandir a escala do software ou de realizar manutenções necessárias. Para nortear o desenvolvimento, provendo melhor reaproveitamento de experiências entre a equipe e facilitando alterações futuras, o desenvolvedor poderá ter em mente alguns dos princípios de projeto de software. Determinados princípios da engenharia de software podem não ter grande efeito em sistemas pequenos, com poucas funcionalidades, visto que algumas dessas técnicas incluiriam complexidade desnecessária ao projeto. Todavia, para sistemas em grande escala, essa complexidade de escrita é compensada pelo tempo economizado no reúso de componentes e na comunicação entre os membros da equipe. Nesta Dica do Professor, conheça os conceitos básicos de padrões de projeto e qual sua finalidade em um projeto de software. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. Exercícios 1) A engenharia de software foi instituída em meados da década de 1960 devido a diversos casos de falhas catastróficas ocasionadas por softwares mal construídos. Ela direciona esforços a diversas áreas do Pensamento Computacional, como as linguagens de programação, padrões, bancos de dados, processos e qualidade de software, dentre outras. Considerando os conceitos e as motivações para a instituição da engenharia de software, assinale a alternativa correta: A) Usar o termo engenharia foi sugerido para aproveitar a fama das engenharias para reduzir a descrença causada pelas falhas dos sistemas. B) A engenharia de software surgiu pela urgente necessidade de correção das falhas ocorridas no software das sondas espaciais. C) A engenharia de software surgiu da necessidade de utilização de princípios de engenharia para a especificação, o desenvolvimento e a manutenção de sistemas de software. D) Tem como principal objetivo a construção de modelos teóricos e fundamentações matemáticas baseados na engenharia clássica. E) Nas últimas décadas, fez a especificação de padrões baseados na engenharia para evitar práticas antigas como reutilização de código. Dentre as contribuições da engenharia de software para a área de desenvolvimento, estão a definição de princípios para construção de projetos. Existem várias definições e autores que tratam do tema. Uma das definições conhecidas são os Sete Princípios de Presmann. Analise as afirmativas a seguir e classifique-as em verdadeiras (V) ou falsas (F): ( ) As decisões tomadas durante a construção do software devem buscar uma meta: agregar valor aos seus usuários. ( ) Os projetos devem se manter tão simples quanto possível e tal tarefa exige muito esforço. ( ) Ao construir um sistema de software, deve-se implementar pensando que mais alguém terá que compreender o que foi feito. ( ) Reúso sempre poupa tempo e esforço; assim, conseguir um alto nível de reúso é a principal meta a ser alcançada. 2) ( ) Raciocinar clara e completamente antes da ação aumenta a probabilidade de funcionar adequadamente. Assinale a alternativa que preenche as lacunas de forma correta: A) V, V, F, V, F. B) F, F, V, F, V. C) V, V, V, F, V. D) V, F, V, F, V. E) V, F, F, V, F. 3) A etapa de Projeto de Software é uma metodologia da engenharia de software que se preocupa com todo o planejamento anterior ao desenvolvimento. Analise as afirmativas a seguir e classifique-as em verdadeiras (V) ou falsas (F): ( ) Considerando os conceitos de construção de software utilizando orientação a objetos, cada componente de software é constituído por uma única classe. ( ) Conforme o Liskov Substitution Principle, caso o componente troque a classe base pela superclasse respectiva, seu funcionamento deve se manter o mesmo. ( ) Quando um componente não depende de classes concretas, e, sim, de abstrações (por exemplo, uma interface), é possível dizer que está seguindo o princípio da inversão de dependência. Assinale a alternativa que preenche as lacunas de forma correta: A) F, F, V. B) V, F, F. C) F, V, F. D) V, V, F. E) F, V, V. O produto construído por meio da engenharia de software tem particularidades distintas de qualquer constructo implementado pelas demais engenharias, em destaque quando são comparados software e hardware. Em seu clássico trabalho denominado "Não Existe Bala de 4) Prata", Frederick Brooks discorreu e elencou problemas inerentes à área da engenharia de software. Considerando os problemas discutidos e a construção de aplicações em larga escala, assinale a alternativa correta: A) O fato de o software não ter forma física é vantagem para o desenvolvedor que pode, de maneira mais simplificada, defender estimativas de esforço junto a seu cliente. B) As dificuldades identificadas por Brooks podem ser classificadas como essenciais e acidentais, mas somente as essenciais são capazes de causar problemas em aplicações reais. C) O impacto de uma adaptação por necessidade de conformidade de uma interface em um sistema é inversamente proporcional ao impacto causado pelo aumento de complexidade de uma aplicação. D) A engenharia de software tem fundamentos básicos inerentes às demais engenharias, sendo que a expressão bala de prata é sempre utilizada em alusão à indústria bélica. E) Os produtos de software estão entre os mais complexos gerados por engenharia e tem dificuldades essenciais intrínsecas, como a complexidade, a invisibilidade e a mutabilidade. A engenharia de software é uma das áreas de estudo que evoluiu consideravelmente os processos voltados à criação de softwares, pois traz conceitos, princípios e padronizações que até hoje são utilizados, servindo de base para a construção de sistemas de alta complexidade. Analise as afirmativas a seguir, que tratam de conceitos gerais sobre engenharia de software, e classifique-as em verdadeiras (V) ou falsas (F): ( ) Um dos problemas do software é que seus processos evoluem muito mais rápido do que aqueles relacionados ao hardware. ( ) Qualquer projeto de software deve ter como meta atender às necessidades de algum negócio. ( ) A engenharia de software não busca desenvolvimento de teorias e fundamentações. Seu objeto de estudo são as práticas de desenvolvimento de software. ( ) Diversos princípios foram definidos pela engenharia de software, tais como a abstração, que filtra os elementos importantes sem ignorar nenhum detalhe. ( ) A engenharia de software não pode ser confundida com a Ciência da Computação, pois, enquanto uma busca teorias e fundamentações para temas computacionais, a outra tem 5) foco na construção de software. Assinale a alternativa que preenche as lacunas de forma correta: A) V, V, F, V, V. B) F, F, V, F, V. C) V, F, F, V, F. D) F, V, V, F, V. E) V, F, V, V, F. Na prática Algumas empresas de software, logo que iniciam sua atuação, em benefícioda rápida entrega e do aumento do número de clientes, optam por não empregar determinadas técnicas da engenharia de software, justamente pela complexidade inicial que algumas delas trazem intrinsecamente. Ao longo do tempo, conforme aumentam a escala dos projetos, o tamanho da equipe e a quantidade de manutenções, fica clara a necessidade de padronizar determinadas atividades em prol de viabilizar o aumento dos projetos e a comunicação entre os membros da equipe. Para tanto, os padrões e os princípios da engenharia de software podem servir de guia para a organização e a implantação de melhorias nos projetos. Acompanhe, neste Na Prática, a utilização de conceitos da engenharia de software para a construção de sistemas em equipes de desenvolvimento. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. Saiba + Para ampliar o seu conhecimento a respeito desse assunto, veja abaixo as sugestões do professor: Conheça os padrões de projeto Neste artigo, são apresentados os padrões de projeto, que propiciam projetar soluções de software com melhor qualidade e menor custo. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. Princípios da engenharia de software Veja, neste artigo, uma introdução à engenharia de software e os sete princípios para a produção de software, segundo o pesquisador David Hooker. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. Padrões de projeto Neste vídeo, conheça um pouco mais sobre os conceitos básicos de padrões de projetos (Design Patterns). Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. SOLID Principles: melhorando o design do seu código Neste artigo, conheça um pouco melhor este conjunto de orientações para a escrita de código que favorece legibilidade, manutenção e evolução do sistema. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. O que é pensamento computacional e para que ele serve? Neste vídeo, conheça um pouco mais sobre Pensamento Computacional. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. A conceptual framework for a software development process based on Computational Thinking Neste artigo, em inglês, acompanhe a apresentação de uma proposta de sistemática para o desenvolvimento de software usando as possibilidades do Pensamento Computacional. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar.