Pular para o conteúdo

Uma regra, três plataformas

A mesma regra de negócio na web (Vitrine), na mesa (Bigorna) e no celular (Brasa) — escrita uma vez, testada uma vez.

Os três frameworks de interface do DataForge têm a mesma forma — o programa da tela roda de cima para baixo, de novo a cada interação — e isso não é coincidência: é o que deixa a regra de negócio morar num módulo sem interface nenhuma, usado igual pelos três.

VitrineBigornaBrasa
onde rodanavegadorjanela nativa (Tk)celular (PWA)
parapainel e aplicação de dadosferramenta de mesaaplicativo no bolso
navegaçãopáginastelas, menus e atalhosabas e voltar
testarV.testarB.testarBr.testar
distribuirservidor.app, .exe, binárioPWA por HTTPS

A regra, uma vez#

dataforge
// estoque.df — nenhum adopt de interface aqui dentro.
record Produto:
    nome: String
    qtd: Integer

action baixar(p: Produto, quanto: Integer) -> Produto:
    given quanto bigger p.qtd:
        trigger $"só há {p.qtd} de {p.nome}"
    yield p with {"qtd": p.qtd - quanto}

action resumo(itens) -> String:
    yield $"{len(itens)} produto(s), {sum([i.qtd cycle i in itens])} unidades"

p := baixar(Produto("café", 12), 2)
assert p.qtd is 10
assert resumo([p]) is "1 produto(s), 10 unidades"
out "a regra não sabe onde vai aparecer"

As três telas#

dataforge
adopt Arcane.Bigorna as B
adopt Arcane.Brasa as Br
adopt Arcane.Vitrine as V
adopt Arcane.OS as OS

record Produto:
    nome: String
    qtd: Integer

action resumo(itens) -> String:
    yield $"{len(itens)} produto(s), {sum([i.qtd cycle i in itens])} unidades"

estoque := [Produto("café", 12), Produto("açúcar", 3)]

// ── na mesa ──
mesa := B.app("Estoque", pasta_de_config := $"{OS.temp_dir()}/df-doc-{randint(100000, 999999)}")
action tela_mesa(t):
    t.titulo("Estoque")
    t.tabela(["nome", "qtd"], [{"nome": p.nome, "qtd": p.qtd} cycle p in estoque])
    t.status(resumo(estoque))
mesa.tela("inicio", tela_mesa)

// ── no celular ──
celular := Br.app("Estoque")
action tela_celular():
    Br.topo("Estoque")
    Br.lista(estoque, titulo := "nome", detalhe := "qtd")
    V.texto(resumo(estoque))
Br.tela("/", tela_celular)

// ── as duas, testadas contra a MESMA regra ──
assert B.testar(mesa).status() is "2 produto(s), 15 unidades"
assert Br.testar(celular).tem("2 produto(s), 15 unidades")
out "uma regra, duas telas, o mesmo resultado"

Num projeto de verdade, a regra fica em src/estoque.df e cada interface a adota com adopt ./estoque as E. Um teste da regra não abre janela nem sobe servidor — e é ele que pega o erro de negócio, antes de qualquer tela.