Jump to content
Fivewin Brasil

Boas Práticas - Compartilhamento


Jmsilva

Recommended Posts

Boas práticas = Uma ajuda sem ninguém pedir

Olá pessoal, sei que este espaço se presta para ajuda direcionada a um objetivo específico, erro ou dúvidas. Pois bem, sabemos que outras linguagens existem materiais farto na internet, já xHarbour  resume-se aos fóruns e nas documentações  própria. Com o conhecimento de outras linguagens como o JAVA, por exemplo, vejo que temos algumas facilidades em determinado pontos e perdemos em outros. Mas com a expertise do dia-a-dia, sempre  descobri mos  técnicas do xHarbour  que não vejo nos fóruns, e nem nos exemplos disponíveis GitHub, Google e etc.

A minha sugestão em boas práticas, refere-se à codificação, boas praticas em programar, não estou falando de regras de negócios, cada um ou cada empresa tem a sua que é a base do seu sistema.

Aqui nos temos grandes programadores, diria os melhores, acredito que cada um tem algo a compartilhar, como uma rotina genérica, forma manipular um objeto e etc.  Posso  citar como exemplo a TCalc, uma classe que desenvolvi  tempos atrás,  serve para gerar planilhas através LibreOficce  está disponível neste fórum.  

Salvo juízo contrário, cada programador poderia compartilhar aquilo que acha interessante que pudesse ajudar no aprendizado dos demais. Com a ajuda dos demais poderia até acrescentar algo para otimizar e favorecendo o próprio autor ou apenas servir de material didático para os demais.

Como ponta pé inicial, gostaria de apresentar uma forma que acho legal para definição de variáveis.

Hipoteticamente, vamos imagina um sistema que tem 3 dbfs, Médico, Paciente e Agenda  de consultas:

#include "hbstruct.ch"  //include obrigatório
REQUEST HB_GT_WIN_DEFAULT
//Definição de 3 objetos , um para cada tabela

Static oMed,oPac,oAgenda 
//pode ser local private, publica – prefiro statica de PRG, assim 
//posso usar em métodos e funções sem a necessidade de enviar como parâmetro, para rotina 
//de  outros prg, a sim precisa enviar via parâmetro.

Procedure Main()
	STRUCTURE oMed //variaveis para tabela de médicos 
		MEMBER cCrm AS STRING INIT Space(6)
		MEMBER cNome AS STRING INIT Space(20)
	ENDSTRUCTURE  
	
	STRUCTURE oPac //variaveis para tabela de pacientes
		MEMBER cCpf AS STRING INIT Space(11)
		MEMBER cNome AS STRING INIT Space(20)
		MEMBER dDtNasc AS DATE INIT CTOD('')	  
	ENDSTRUCTURE  
	
	STRUCTURE oAgenda //variaveis para tabela de agendamento de consulta
		MEMBER cCrm AS STRING INIT Space(6)
		MEMBER cCpf AS STRING INIT Space(11)
		MEMBER dDtConsulta AS DATE INIT CTOD('')	  	  
	ENDSTRUCTURE  
	
	//gets e says e gravações
	
	
Return

 

Link to comment
Share on other sites

  • 3 weeks later...

Quanto a estruturas para não misturar as variaveis eu utilizo outra técnica que eu particularmente prefiro. A técnica que uso é a seguinte:

Todas as tabelas criadas eu identifico por 3 letras seguidas de mais 4 digitos para identificar a empresa. Quando a tabela é uma tabela compartilhada entre as empresas eu mantenho como padrão a empresa 0001. Também identifico no sistema essa tabela somente pelas 3 letras iniciais da tabela. Dentro desta tabela os campos eu crio sempre começando pelo alias e depois o underline e os demias 6 caracteres identificam o nome do campo. (aprendi desta maneira na Microsiga/TOTVS e gostei por isso continuo assim até hoje)

Departamentos (tabela unica para todas as empresas) => Nome da tabela SA10001 => Identificador de alias dentro do programa SA1. Estrutura de campos:

CODIGO => SA1_CODIGO (Caracter 6)

NOME DO DEPARTAMENTO => SA1_NOME (caracter 30)

 

Funcionarios (tabela exclusiva de cada empresa) => Nome da tabela SA20001, SA20002, SA20003,...,SA29999. Identificador de alias dentro do programa SA2. Estrutura de campos:

CODIGO => SA2_CODIGO (caracter 5)

NOME => SA2_NOME (caracter 40)

DEPARTAMENTO => SA2_CODDEP (caracter 6)

 

Com estas regras eu nunca preciso me preocupar com campos repetidos pois eles nunca se repetem pois o campo NOME do departamento é sempre o SA1_NOME e o nome do funcionário é o SA2_NOME

Também sigo outra regra sobre os indices. Sempre é caracter, caso o campo seja numero eu o transformo com STR ou DTOS para data. Desta maneira o indice sempre fica do tipo CARACTER

No fonte fica mais ou menos assim:


Function u_Teste()

DbSelectArea("SA1")
M->SA1_CODIGO := SA1->SA1_CODIGO
M->SA1_NOME   := SA1->SA1_NOME


DbSelectArea("SA2")
M->SA2_CODIGO := SA2->SA2_CODIGO
M->SA2_NOME   := SA2->SA2_NOME
M->SA2_CODDEP := SA2->SA2_CODDEP
cDesDep       := RetField("SA1",1,M->SA2_CODDEP,"SA1_NOME")




// A funcão RETFIELD trata de selecionar a area do cPar1, posicionar no indice do nPar2, fazer o dbseek no cPar3 e retornar o campo através de macro do cPar4

 

Link to comment
Share on other sites

Não tenho muito a contribuir, até porque mais preciso de ajuda do que posso ajudar. No entanto, tem algumas dicas que aprendi com colegas do fórum que vale a pena repassar:

Primeiramente, no que se refere à definição de variáveis, gosto de usar o estilo “forma de camelo”, isto é, usar minúsculas e maiúsculas nas definições de variáveis.

Por exemplo

cObs := “” // e não cobs := “”

Em segundo lugar, sempre endentar o código (usar espaços ou tabulação), para não parecer bagunçado e difícil de compreender, bom como inserir comentários, principalmente quando sinto que vou precisar lembrar de alguma anotação mais adiante.

Exemplo:

Local cObser := “” // Mostrar apenas se cObser não estiver vazia.
IF Empty(nomeClient)
   IF Empty(cObser)
      cObser += “; “ + CRLF // Quebrar a linha caso exista mais de uma inconsistência 
   ENDIF
   cObser += “• O nome do cliente deve ser informado”
ENDIF

Em vez de:

Local cObser := “”
If Empty(nomeClient)
If Empty(cObser)
cObser += “; “ + CRLF
EndIf
cObser += “• O nome do cliente deve ser informado”
EndIf

E, em terceiro lugar, tomar muito cuidado com o famoso “enxugar o código”. Resumir três ou mais linhas de código em apenas, às vezes, uma é muito bom.

Ex.1: nNumero++ // em vez de nNumero := nNumero + 1

Ex.2: cImg := Iif(nPic = 3, “bmpTres”, Iif(nPic = 2, “bmpDois”, “bmpUm”))

Em vez de:

cImg := “”
IF nPic = 1
   cImg := “bmpUm”
ELSEIF nPic = 2
   cImg := “bmpDois”
ELSE
   cImg := “bmpTres”
ENDIF

Mas quando se trabalha em equipe, enxugar demais pode deixar o código complicado para o entendimento dos colegas, por isso, prefira, para o bem de todos, deixar o código menos complicado possível, mesmo que isso signifique abrir mão da técnica de enxugar o código.

Note também que eu gosto de iniciar a declaração de variáveis com uma letra que identifique o tipo de conteúdo dela:

STATIC oXbrItn := NIL // Objeto - Ex: XBrowse() a ser definido
LOCAL nCodigo := 0 // Numérica
LOCAL cDesItn := Space(80) // Caractere / String
LOCAL mDetalh := "" // Memo / String
LOCAL dCadast := CtoD(" ") // Data
LOCAL lLockIt := .F. // Lógica

Por fim, conforme dá para notar acima, gosto de utilizar como boa prática algo que me permita diferenciar "Function()" de "COMMAND". Para isso, gosto de fazer bom uso das minúsculas e maiúsculas. Por exemplo, escrever Funções com iniciais maiúsculas ou usando o “estilo camelo”, e comandos com todas MAIÚSCULAS.

É claro que nem sempre lembro de seguir todas essas regrinhas, afinal, ninguém é perfeito. Também nem toda IDE de desenvolvimento permite isso. O bom é que existem muitas IDEs com recursos de endentação automática, auto-complete e auto-case (estilo camelo automático). Com elas, esse tipo de técnica manual está sendo automatizado, permitindo a gente se concentrar mais na codificação em si.

Link to comment
Share on other sites

Em linguagem como Java por exemplo, uma variável declarada do tipo String se transforma em um objeto, como no exemplo que segue:

String txt = "Hello World";
System.out.println(txt.toUpperCase());   // Outputs "HELLO WORLD"
System.out.println(txt.toLowerCase());   // Outputs "hello world"

No xHarbour/Harbour podemos fazer melhor, mas vou demostrar forma nativa, não conheço todos os métodos/eventos, estou pesquisando. É possível utilizar em qq tipo de variável, e podemos fazer  melhor que o Java, que necessita declarar no escopo o TIPO, no nosso velho (x)Harbour, as propriedades são em consequência ao valtype() do CONTEÚDO da variável. O comando mágico para esta façanha é:

ENABLE TYPE CLASS ALL

Veja exemplo nativo com manipulação de uma variável do tipo Array:

ENABLE TYPE CLASS ARRAY                  
aVar := {}                               //Modo tradicional
aVar:Init(3,Array(2))                    //aVar := Array(3,2)
aVar:AtPut(1,{"001", "Maça"} )           //aVar[1,{"001", "Maça"} )      
aVar:AtPut(2,{"002", "Pera"} )           //aVar[2,{"002", "Pera"} )   
aVar:AtPut(3,{"003", "Uva"} )            //aVar[3,{"003", "Uva"} )   
aVar:InsertAt(4,{"004","Morango"})       //AADD(aVar,{"004", "Morango"} )   
XBrowse(aVar )                           //xBrowse(aVar)

  Dica do dia!

Link to comment
Share on other sites

  • 1 month later...
Function ViaCep()
   Local oOle,cXml,cCep := "01302001"
   Local cLink := "http://viacep.com.br/ws/<<CEP>>/xml/"
   Local oXml,oTag,cLog,cComple,cBairro,cCidade,cUf

   cLink := StrTran(cLink,"<<CEP>>",cCep)

   BEGIN SEQUENCE
      Try
         oOle := CreateObject("Msxml2.XMLHTTP.3.0")
         oOle:Open("GET",cLink,.F.)
         oOle:Send()
         cXml := oOle:ResponseBody
         oOle := nil
      Catch
         BREAK
      End

      //verifica se não encontrou o cep atraves tag "erro"
      oXml := TXmlDocument():New(cXml)
      oTag := oXml:findFirst("erro")
      If !Empty(oTag) .and. oTag:cData == "true"
         MsgStop("CEP não encontrado !")
         BREAK
      Endif

      oTag := oXml:findFirst("logradouro")
      cLog := IIF(Empty(oTag),'',oTag:cData)

      oTag := oXml:findFirst("complemento")
      cComple := IIF(Empty(oTag),'',oTag:cData)

      oTag := oXml:findFirst("bairro")
      cBairro := IIF(Empty(oTag),'',oTag:cData)

      oTag := oXml:findFirst("localidade")
      cCidade := IIF(Empty(oTag),'',oTag:cData)

      oTag := oXml:findFirst("uf")
      cUf := IIF(Empty(oTag),'',oTag:cData)

      XBrowse({cLog,cComple,cBairro,cCidade,cUf})

  END SEQUENCE


Return {cLog,cComple,cBairro,cCidade,cUf}

Pesquisa de CEP OnLine!

Link to comment
Share on other sites

  • 1 month later...
Function ViaCep()
   Local oOle,cJSon,cCep := "91312001"
   Local cLink := "http://viacep.com.br/ws/<<CEP>>/json/"
   Local hResp := Hash()

   cLink := StrTran(cLink,"<<CEP>>",cCep)

   BEGIN SEQUENCE
      Try
         oOle := CreateObject("Msxml2.XMLHTTP.3.0")
         oOle:Open("GET",cLink,.F.)
         oOle:Send()
         cJSon := oOle:ResponseBody
         oOle := nil
      Catch
         BREAK
      End

      HB_JsonDecode(cJSon,@hResp)  
      
      IF HHasKey(hResp, "erro" )
         MsgStop("Cep não localizado !")
      Endif
      XBrowse(hResp)
  END SEQUENCE
      
Return hResp

#BoasPraticas

Link to comment
Share on other sites

  • 7 months later...

Boas práticas de hj  é sobre pesquisa INCREMENTAL em TBrowse com uso BackGound -  Rotina em segundo plano.

Tenho interesse por processamento paralelo e BackGround, o primeiro não consegui ainda, sei que tem parâmetros para incluir na compilação, mas não deu certo, o segundo consegui, no caso a rotina abaixo está rodando tbrowse() em uma tabela 'temp' indexada por nome, ao precionar F3 abre get para digitar e o conteúdo GET vai "Refresh() ando"  no Browse.

Se curtiu tecle "Joinha" 

 

oTB:ForceStable()
nKEY := Inkey(0)

IF nKEY == K_ESC
	EXIT
ELSEIF nKEY == K_F3
  /*processamento em segundo plano*/
  HB_IdleAdd( {|| HB_BackGroundRun() } )
  nTask := HB_BackGroundAdd( {|| RefreshTB(oTB) }, 1000 )
  SET BACKGROUND TASKS ON
  /*------------------------------*/
  cChave := Space(35)
  //BOX3DOF(14,16,18,58)
  @ 14,16 clear to 18,58
  DispBox(14,16,18,58,2,"n/b")
  @ 16,20 GET cChave PICT "@!"
  READ
  HB_BackGroundDel( nTask )
  oTB:RefreshAll()
Endif  

**----------------------------------------------------------------------
Function RefreshTB(oTB)   //fica rodando BackGround
**----------------------------------------------------------------------
Local cTela,oGet:=GetActive()
Static cLast := ''

If HB_IsObject(oGet) .and. cLast != oGet:buffer
  cTela := SaveScreen(14,16,18,58)
  TEMP->(DBSEEK(oGet:buffer,.T.))
  oTB:RefreshAll()
  oTB:ForceStable()
  Restscreen(14,16,18,58,cTela)
  cLast := oGet:buffer
  oGet:SetFocus()
Endif

Return .t.

xHarbour/Harbour, FiveWin, SqlRdd e Pelles C -  Editor xEdit

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...