tdc2014 sp - c/c++ - modularização de código c

10
GESTÃO DE PATRIMÓNIO Gestão Técnica de Manutenção de Edificios

Upload: felipe-de-andrade-neves-lavratti

Post on 05-Jun-2015

433 views

Category:

Technology


0 download

DESCRIPTION

Apresentação feita dia 09/08/2014 na TDC de SP sobre modularidade de código C.

TRANSCRIPT

Page 1: TDC2014 SP - C/C++ - Modularização de Código C

Click to add Text

Globalcode – Open4education

C/C++ – Modularização de Código CFelipe de Andrade Neves Lavratti

Me. Eng.º Eletricista desenvolvedor de softwarepara Sistemas Embarcados

9 de agosto de 2014 – São Paulo – SP

Page 2: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Experiência do Apresentador

http://www.embarcados.com.br

9 ago 2014 2 / 44

Page 3: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Principal bibliografia

Capítulo 11:SOLID em C, mas sem OOP;

Módulos mais complexose completos do que os propostos;

9 ago 2014 3 / 44

Page 4: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Agenda

Introdução

Porque modularizar

Exemplo

Quatro regras da modularização proposta

A composição do módulo

Usando o módulo “rectangle”

Demais tipos de módulos propostos

Módulo “vector”

Módulo “framebuffer”

Usando o módulo “vector” e “framebuffer”

9 ago 2014 4 / 44

Page 5: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Modularizar é uma metodologia de arquitetura de software.

O principal objetivo é manter o código organizado, legível e desacoplado.

A modularização tem como sua principalregra o SRP (Single Responsibility Principle)

e dependência em abstrações.

9 ago 2014 5 / 44

Page 6: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Não é OOP porque não suporta herança e polimorfismo facilmente.

Mas é OBP, programaçãobaseada em objetos.

9 ago 2014 6 / 44

Page 7: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Porque modularizar

9 ago 2014 7 / 44

Page 8: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Porque modularizar?

Por que permite a criação de excelentes arquiteturas:

Design patterns* podem ser aplicados

Cria alicerces para boas práticas de programação:Como, testes unitários, eliminação de código repetido, abstração por interfaces, SOLID, incremento na semântica, etc.

*variações ou simplificações de design patterns ou completos se implementar OOP manualmente.

9 ago 2014 8 / 44

Page 9: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Exemplo

A seguir função retirada da firmware de um produto real onde a modularidade não foi empregada.

Depois um exemplo de como ficaria a mesma função se usada a metodologia de modularização proposta.

9 ago 2014 9 / 44

Page 10: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Exemplo: sem modularização.

Trecho de código repetido ao longo da

firmware. Dependência em implementação

Semântica obscura

9 ago 2014 10 / 44

Page 11: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Exemplo: com modularização.

Dependência em abstração

Semântica incrementada

9 ago 2014 11 / 44

Page 12: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Quatro regras damodularização proposta

9 ago 2014 12 / 44

Page 13: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

RegrasSingle Responsibility Princple (SRP)

Um módulo deve fazer uma coisa, e fazê-la bem.

Dependência em abstraçãoCódigo deve depender de uma funcionalidade, e não de uma implementação.

Nomenclatura descritivaSe um módulo e suas funções são bem nomeados, sua funcionalidade fica clara.

Interface é documentaçãoSe todos os itens anteriores são obedecidos, então a interface pode ser a única documentação necessária.

9 ago 2014 13 / 44

Page 14: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

A composiçãodo módulo

9 ago 2014 14 / 44

Page 15: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

INTERFACE

IMPLEMENTAÇÂO

DADOS

Composição do Módulo

Implementação (arquivo .c)Implementação das funções, definição dos tipos privados, comentários sobre a implementação.

Dados (struct)É o tipo do módulo, quando existir, deve ser sempre privado. Contém todos os dados relevantes, como instâncias, buffers, etc.

Interface (arquivo .h)Funções de acesso, definições de tipos e comentários sobre a abstração.

9 ago 2014 15 / 44

Page 16: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Composição: DadosArquivo rectangle.c – projeto marsh – commit 7b4986ahttps://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.c

#include “rectangle.h”

...

struct s_rectangle_instance{

color_t fill_color;bool is_filled;color_t border_color;dim_t border_tickness;bool has_border;dim_t corner_radius;...

};

...

O tipo é definido por uma struct,

seus membros são privados, não podem ser acessados pelos clientes diretamente.

todos os dados necessários para a operação do módulo ficam contidos nessa struct,

9 ago 2014 16 / 44

Page 17: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Composição: Interface

#ifndef RECTANGLE_H_#define RECTANGLE_H_

typedef struct s_rectangle_instance rectangle_t;

rectangle_t * rectangle_new(widget_t * parent);void rectangle_delete(rectangle_t * const);

void rectangle_set_position(rectangle_t * const, dim_t x, dim_t y);void rectangle_set_size(rectangle_t * const, dim_t width, dim_t height);void rectangle_set_fill_color_html(rectangle_t * const, const char * html_color_code);void rectangle_set_border_tickness(rectangle_t * const, dim_t tickness);void rectangle_set_border_color_html(rectangle_t * const, const char *html_color_code);void rectangle_set_rounded_corner_radius(rectangle_t * const, dim_t radius);

...

#endif /* RECTANGLE_H_ */

Arquivo rectangle.h – projeto marsh – commit 7b4986ahttps://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.h

Funções de criação e destruição.

Funções de funcionalidades.

Declaração do tipo,

9 ago 2014 17 / 44

Page 18: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

O módulo: Interface

#ifndef WIDGET_TREE_H_#define WIDGET_TREE_H_

... 

/* This method delete a widget, its creator, and all tree behind it, * including the creator of each node. * Ownership of obj and its children is transferred */void widget_tree_delete(widget_t * obj); 

...

#endif

Arquivo widget_tree.h – projeto marsh – commit 7b4986ahttps://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/widget_tree.h

Na interface comentários relacionados a abstração, como:

“o que faz” (não “como faz”);o que é esperado dos

parâmetros;se a posse de algum tipo é

transferida;etc.

9 ago 2014 18 / 44

Page 19: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Comp.: ImplementaçãoArquivo rectangle.c – projeto marsh – commit 7b4986ahttps://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.c

#include “rectangle.h”...rectangle_t * rectangle_new(widget_t * parent){

rectangle_t * obj = (rectangle_t *) calloc(1, sizeof(struct s_rectangle_instance));

MEMORY_ALLOC_CHECK_RETURN(obj, NULL);...return obj;

}void rectangle_delete(rectangle_t * const obj){

PTR_CHECK(obj, "rectangle"); 

my_log_delete(obj->log);widget_delete_instance_only(obj->glyph);

 free(obj);

}...

Sem globais nem variáveis static, para manter a reentrância.

Implementa as funcionalidades do módulo.

rectangle_new e rectangle_delete fazendo malloc para esconder dados do rectangle_t do cliente;

9 ago 2014 19 / 44

Page 20: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Usando omódulo “rectangle”

9 ago 2014 20 / 44

Page 21: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Usando o rectangle

rectangle_t * rect;

rect = rectangle_new(NULL); /* Alloc a new rectangle */if (!rect) { perror(“Unable to alocate a rectangle”); }

/* Set rectangle positon to (10,10) */rectangle_set_position(rect, 10, 10);

rectangle_delete(rect); /* delete the rectangle */rect = NULL;

Exemplo de uso do módulo rectangle:

9 ago 2014 21 / 44

Page 22: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

#ifndef RECTANGLE_H_#define RECTANGLE_H_

typedef struct s_rectangle_instance rectangle_t;

rectangle_t * rectangle_new(widget_t * parent);void rectangle_delete(rectangle_t * const);

void rectangle_set_position(rectangle_t * const, dim_t x, dim_t y);void rectangle_set_size(rectangle_t * const, dim_t width, dim_t height);void rectangle_set_fill_color_html(rectangle_t * const, const char * html_color_code);void rectangle_set_border_tickness(rectangle_t * const, dim_t tickness);void rectangle_set_border_color_html(rectangle_t * const, const char *html_color_code);void rectangle_set_rounded_corner_radius(rectangle_t * const, dim_t radius);

...

#endif /* RECTANGLE_H_ */

Usando o rectangleArquivo rectangle.h – projeto marsh – commit 7b4986ahttps://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.h

forward declaration

9 ago 2014 22 / 44

Page 23: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Usando o rectangle

rectangle_t * rec = rectangle_new(NULL);rec->has_border;

Acessando os membros internos de rectangle diretamente não compila:

rectangle_t rect;

Porém usar rectangle_t na stack também não compila:

error: forward declaration of ‘rectangle_t {aka struct s_rectangle_instance}’

error: aggregate ‘rectangle_t rect’ has incomplete type and cannot be defined

Como rectangle_t é uma forward declaration, os membros internos da struct do módulo são invisíveis ao código do cliente.

9 ago 2014 23 / 44

Page 24: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Demais tipos de módulos propostos

9 ago 2014 24 / 44

Page 25: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Tipos de módulosQuanto a instância:

de instância única;

ou multiplamente instanciável.

Quanto ao local da instância:no heap somente;

ou no heap ou stack.

Quanto à implementação variável:de implementação fixa;

ou selecionável na compilação;re

cta

ng

le

vec

tor

fra

me

bu

ffe

r

9 ago 2014 25 / 44

Page 26: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Módulo vector(instância na stack)

9 ago 2014 26 / 44

Page 27: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Instância na stackA struct privada do módulo precisa ser visível ao código do cliente.

Pode ter seus membros internos acessados sem erro no compilador.

Informe ao cliente que aqueles dados são privados:

Usando um header com nome “_private.h”

Nomeando a struct com “_private”

Acrescentando comentário na struct

E até colocando “__” nos nomes dos membros da struct privada.

9 ago 2014 27 / 44

Page 28: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Interface do vectorArquivo vector.h – projeto chelper – commit 4273eed http://github.com/felipe-lavratti/chelper/blob/4273eedd76d8fb6dc22dd978abad5ab7636bf39b/include/chelper/vector.h

#ifndef VECTOR_H_#define VECTOR_H_

#include "private_helper_types.h“...typedef struct s_vector_private vector_t; void vector_init(vector_t *, size_t item_size);void vector_deinit(vector_t *);

size_t vector_size(vector_t *);BUFFER_PTR vector_at(vector_t *, size_t pos);

void vector_add(vector_t *, BUFFER_PTR_RDOLY item);void vector_remove(vector_t *, size_t pos);void vector_clear(vector_t *);

...#endif /* VECTOR_H_ */

Indicação de dados privados no nome

Não é forward declaration

Não fazem malloc/free

Usam vector_t alocado pelo cliente

9 ago 2014 28 / 44

Page 29: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Dados privadosArquivo private_helper_types.h – projeto chelper – commit 4273eedhttp://github.com/felipe-lavratti/chelper/blob/4273eedd76d8fb6dc22dd978abad5ab7636bf39b/include/chelper/private_helper_types.h

#ifndef PRIVATE_HELPER_TYPES_H_#define PRIVATE_HELPER_TYPES_H_/** All types defined in this header should never be directly derreferenced nor* have its member accessed by external code. These are private data belonging to* internal modules only.** Each of these structs has a non forward typedef meant to be allocated by client* code and used only through chelper's public functions.*/struct s_vector_private{ /* This data is private, do not touch it */ size_t __item_size; uint32_t __used_slots; uint32_t __buffer_total_slots; uint8_t * __buffer;};...#endif /* PRIVATE_HELPER_TYPES_H_ */

9 ago 2014 29 / 44

Page 30: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Implementação do vectorArquivo vector.c – projeto chelper – commit 4273eed http://github.com/felipe-lavratti/chelper/blob/4273eedd76d8fb6dc22dd978abad5ab7636bf39b/lib/vector.c

#include “chelper/vector.h”...void vector_init(vector_t * cobj, size_t item_size){

struct s_vector_private * obj = (struct s_vector_private *)cobj;PTR_CHECK(obj, "vector");

 obj->__item_size = item_size;

 obj->__buffer = (uint8_t *)calloc(2, obj->__item_size);MEMORY_ALLOC_CHECK(obj->__buffer);obj->__buffer_total_slots = 2;

 obj->__used_slots = 0;

}void vector_deinit(vector_t *cobj){

struct s_vector_private * obj = (struct s_vector_private *)cobj;PTR_CHECK(obj, "vector");

 if (obj->__buffer) {

free(obj->__buffer);obj->__buffer = NULL;

}}

9 ago 2014 30 / 44

Page 31: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Módulo framebuffer(instância única e

implementação selecionável)

9 ago 2014 31 / 44

Page 32: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Instância únicaTipo não é alocável pelo cliente.

É interno e static.

Não é reentrante.

9 ago 2014 32 / 44

Page 33: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Interface do framebufferArquivo framebuffer.h – projeto marsh – commit 7b4986a http://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/framebuffer.h

#ifndef FRAMEBUFFER_H_#define FRAMEBUFFER_H_

void framebuffer_init(void);void framebuffer_deinit(void);

pixel_t *framebuffer_start(void);pixel_t *framebuffer_at(pixel_t x, pixel_t y);

size_t framebuffer_width(void);size_t framebuffer_height(void);

const area_t * framebuffer_area(void);

void framebuffer_inform_written_area(size_t x, size_t y, size_t width, size_t height);

#endif /* FRAMEBUFFER_H_ */

Não tem parâmetro de instância.

9 ago 2014 33 / 44

Page 34: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Interface do framebufferArquivo framebuffer.c – projeto marsh – commit 7b4986a http://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/platform_src/test_mocks/framebuffer.c

#include "framebuffer.h“#include "area.h“...static pixel_t* pFb;... void framebuffer_init(){ if (!_fb_not_initd()) free(pFb); pFb = (pixel_t *)calloc(FRAMEBUFFER_HEIGHT * FRAMEBUFFER_WIDTH, sizeof(pixel_t));}void framebuffer_delete(){ if (_fb_not_initd()) return; if (pFb) free(pFb); pFb = NULL;}...

Dados privados, nesse caso é só um apontador.

Módulo independente de plataforma pode ser usado em código dependente de plataforma.

9 ago 2014 34 / 44

Page 35: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Implementação selecionávelA implementação é escolhida na compilação, pelo Makefile.

Todas implementam a mesma interface

Apenas uma interface de acesso ao módulo

Diversas implementações são possíveis.

Comumente usado para organizar código multi-plataforma sem #ifdefs.

9 ago 2014 35 / 44

Page 36: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Organização de pastas para código multi-plataforma

Código dependente de plataforma

Código independente de plataforma

9 ago 2014 36 / 44

Page 37: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Organização de pastas

Arquivos de implementação são escolhidos de acordo com o target do Makefile

Nome ruim, não passa a funcionalidade para o cliente, thread não diz respeito à abstração, e sim à implementação.

Para o código cliente do framebuffer, não pode haver diferença de uso se compilado para test_mocks ou linux_simulator.

9 ago 2014 37 / 44

Page 38: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Usando omódulo vector e framebuffer

9 ago 2014 38 / 44

Page 39: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Usando o vector

#include <chelper/vector.h>

vector_t * vect_heap = malloc(sizeof(*vect_heap));vector_t vect_stack;

vector_init(vect_heap, ...);vector_init(&vect_stack, ...);

vect_heap->__item_size = 3;vect_heap.__item_size = 3;

...

vector_deinit(vect_heap);free(vect_heap);vect_heap = NULL;

vector_deinit(&vect_heap);

Exemplo de uso do módulo vector, alocando no heap e na stack:

Mesmo esses acessos sendo considerados ilegais, esse código compila.

9 ago 2014 39 / 44

Page 40: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Usando o framebuffer

#include “framebuffer.h”

framebuffer_init();

...

pixel_t * fb_point = framebuffer_at(100, 20);

...

framebuffer_deinit();

Exemplo de uso do módulo framebuffer:

9 ago 2014 40 / 44

Page 41: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Referências

9 ago 2014 41 / 44

Page 42: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Test-Driven Development for Embedded CJames W. Grenning

Para um excelente conteúdo sobre unit-testing e arquitetura modularizada. A leitura do capítulo 11 “SOLID, Flexible, and Testable Designs” é altamente recomendada.

Design Patterns for Embedded Systems in CBruce Powel DouglassComo excelente referência de patterns em C para o emprego prático da modularidade.

Referências

9 ago 2014 42 / 44

Page 43: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Projeto Marsh e Projeto ChelperAmbos são exemplos das técnicas de modularidade apresentadas.http://github.com/felipe-lavratti

Chelper é uma biblioteca de extensão da linguagem C, com código frequentemente utilizado (vector, linked list, signal/slot, etc.)

Marsh é uma interface gráfica auto contida, independente de OS e escrito em C, para rodar tanto em firmware baremetal quanto sobre sistemas operacionais.

CONTRIBUIDORES SÃO BEM VINDOS!

Referências

9 ago 2014 43 / 44

Page 44: TDC2014 SP - C/C++ - Modularização de Código C

Globalcode – Open4education

Modularização de Código C

Muito obrigado!

Dúvidas?

felipelav no gmail

9 ago 2014 44 / 44