
Mais recentemente, publicamos
um artigo descrevendo os problemas de uma das tecnologias mais populares usadas em TI e, para nossa surpresa, despertou um interesse bastante animado (pelo menos para um artigo técnico). Portanto, decidimos não parar por aí e hoje vamos "visitar" um dos produtos mais populares no mercado russo para o desenvolvimento de aplicativos de negócios - a plataforma 1C.
Aconteceu que muitos 1Cs não gostam no hub, mas às vezes parece que poucas dessas pessoas entendem bem, das quais não gostam dele. Com este artigo, preenchemos essa lacuna e matamos dois coelhos com uma cajadada: por um lado, mostraremos como tudo funciona em 1C por dentro e, por outro lado, por que não funciona como deveria / seria desejável. Devo dizer que o 1C com muitas de suas decisões pode realmente nos surpreender, no entanto, não vamos nos antecipar.
Existem artigos suficientes criticando 1C em Habré (por exemplo,
um ,
dois ,
três ), mas, na minha opinião, eles prestam muita atenção a todas as pequenas coisas, como o menu está incorretamente organizado, ou falam sobre coisas muito abstratas nas quais 1C é possivelmente e não culpar. No mesmo artigo, assim como no artigo sobre SQL, focaremos exclusivamente problemas fundamentais (e bastante tangíveis) que dizem respeito a todos e a todos que desenvolvem / refinam soluções em 1C e levam a um aumento significativo no limiar de entrada ou a um sério problema. uma queda na produtividade ou custos significativos de mão de obra por parte do desenvolvedor.
Então vamos lá. Existem muitos problemas no 1C, portanto, para facilitar a navegação, começamos com um sumário (com uma lista de todos esses problemas):
Tentei construir as seções em ordem, desde conceitos básicos / problemas até conceitos mais complexos, embora na maioria das vezes eles não estejam de forma alguma conectados um ao outro. Portanto, se alguém estiver com preguiça de ler o artigo inteiro, basta ler as seções individuais de seu interesse no sumário, praticamente não há plotagem transversal.
Objetos: Diretórios, Documentos, etc.
Como as estruturas / plataformas ORM geralmente são organizadas? Na linguagem de desenvolvimento da estrutura ORM, as classes de objetos são suportadas de uma forma ou de outra. Para cada uma dessas classes, o desenvolvedor pode especificar seu mapeamento para alguma tabela. Como regra, uma classe corresponde a uma tabela, cuja única chave, por sua vez, corresponde ao identificador de um objeto dessa classe. Aqui, é claro, surge a questão do que fazer com tabelas que possuem várias chaves. Classes correspondentes também são criadas para elas, uma vez que a maioria dos ORMs suporta vários campos da mesma classe que identificadores. Às vezes, é claro, com esse mapeamento, temos abstrações bastante detalhadas como o CommodityWarehouse, mas na maioria dos casos os dados são manipulados no mesmo paradigma (OOP).
Em 1C, eles decidiram seguir o outro caminho e apoiar os dois paradigmas de uma só vez, eles simultaneamente tinham objetos e registros. A lógica dos registros é usada por registros e consultas (sobre eles nas seções a seguir); a lógica dos objetos se assemelha a um ORM regular, no entanto, com características próprias:
- O desenvolvedor não controla a exibição nas tabelas e, em geral, está oculta (embora não haja nada de especial)
- Não existem mapeamentos um para muitos, muitos para muitos; sua função é desempenhada pelas chamadas partes tabulares - coleções de objetos internos que são realmente agregados ao objeto principal.
Recuperação ineficiente de dados do objeto
Como a leitura prematura ou excessiva dos dados do servidor de banco de dados e a transferência para o servidor de aplicativos pode levar a uma queda significativa no desempenho, geralmente as estruturas ORM fornecem ao desenvolvedor todo um conjunto de ferramentas para gerenciar os dados recebidos. Mas não 1C. Em 1C, um objeto é sempre lido na íntegra, inclusive com partes tabulares, mas não mais (sem dados associados). Como resultado, os dados são lidos:
- ou muito - se você precisar obter apenas um campo (adereços)
- ou muito pouco - se no loop você precisar acessar outros objetos por referência, obteremos o problema clássico de N + 1 (uma solicitação para obter N objetos e uma solicitação para cada link).
Essa miséria do mecanismo ORM em 1C é realmente devido ao fato de que em 1C eles decidiram simplesmente abandonar o ORM e confiar no SQL (ou seja, registros e consultas). É verdade que, olhando um pouco à frente, dada a falta de recursos avançados de SQL e DML no 1C, eles retornam periodicamente ao ORM, mas isso é uma necessidade necessária. Mas, em geral, um código típico de soluções típicas em 1C é mais ou menos assim:
Exemplo de código (, , = )
////////////////////////////////////////////////////////////////////////////
//
= ;
(, );
////////////////////////////////////////////////////////////////////////////
//
= ;
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
0(, , );
(, , );
(, , );
(, , );
(, , );
(, , );
.(, , ., );
(, , )
= "";
.(, )
"";
;
=
"
| (.) ,
| & ,
| . ,
| . ,
| . ,
|
| . (10, 14)
| .
| (..)
| ,
| . ,
|
| .. ((..), (..))
| .
| (..)
| ,
| 0 ,
| . ,
| .
|
| ..
|
| . = &
| . <> 0
| & <> (..)
| &
| &
|
|
|
|
| (.),
| &,
| .,
| .,
| .,
|
| . (10, 14)
| .
| (..)
| ,
| .,
|
| .. ((..), (..))
| .
| (..)
| ,
| .,
| .,
| .
|
| ..
|
| . = &
| . <> 0
| & = (..)
| &
| &
|
|
|
|
| (.),
| &,
| .,
| .,
| .,
|
| . (10, 14)
| .
| (..)
| ,
| .,
|
| .. ((..), (..))
| .
| (..)
| ,
| 0,
| .,
| .
|
| ..
|
| . = &
| . = 0
| &
| &
|
|
|
|
| (.),
| &,
| .,
| .,
| .,
|
| . (10, 14)
| .
| (..)
| ,
| .,
|
| .. ((..), (..))
| .
| (..)
| ,
| 0,
| .,
| .
|
| ..
|
| . = &
| . = 0
| &
| &";
.(, );
;
/ :
1 , :
- . — , — , () ( )
— ERP- 1 . , SQL ( ), , — , . 1 , , , . — . ( 1 ).
1 :
SQL, , 1 ( )
SQL.
, 1 : , . , MS SQL, Oracle. , , — ( / ) () .
( ), SQL : 1 , , / , / , ( ).
1 , , . , , 0, - . SQL , 1 . ? , , :
( SQL per-statement trigger on before) :
// ,
// .
= ;
.("", ..);
. = ...;
. =
"
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
|
| . = (.)
| . + .
| -. - .
| ,
|
| . = (.)
| .
| -.
| ,
|
| . = (.)
| -.
| .
| ,
|
| . = (.)
| -.
| .
|
|
|
| .
|
| . = &";
.();
(on after) + :
= ..;
= ;
= ..() = ..;
.("", );
.("", ..);
. = .;
//
// .
. =
"
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| (.) ,
| (.) ,
| (.)
|
|
| (
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| .
|
|
|
|
|
|
| .,
| .,
| .,
| .,
| .,
| .,
| .,
| .,
|
| . = (.)
| -.
| .
| ,
|
| . = (.)
| .
| -.
| ,
|
| . = (.)
| .
| -.
|
|
| .
|
| . = &)
|
|
| .,
| .,
| .,
| .,
| .,
| .,
| .,
| .
|
|
| ((.) > 0
| (.) > 0
| (.) > 0)
|;
|
|////////////////////////////////////////////////////////////////////////////////
|
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| (.)
|
|
| (
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| . ,
| -.
|
|
|
| . <> (..)
| ..
|
|
|
|
| .,
| .,
| .,
| .,
| .,
| .,
| .,
|
| . = (.)
| . + .
| -. - .
|
|
| .
|
| . = &)
|
| . <> (..)
| ..
|
|
| .,
| .,
| .,
| .,
| .,
| .,
| .
|
|
| (.) > 0
|;
|
|////////////////////////////////////////////////////////////////////////////////
| ";
= .();
= [0].();
.();
// .
// .
.("", . > 0);
= [1].();
.();
.("", . > 0);
( ) , 0.
(,"")
.((""));
= +
"
|
| . ,
| .. ,
| . ,
| . ,
| . ,
| . ,
| (.)
|
|
|(
| . ,
| . ,
| . ,
| . ,
| . ,
| -. - .
|
| ..(
| ,
| (, , , , )
| (
| .,
| .,
| .,
| .,
| .
|
| ))
|
|
|
| . ,
| . ,
| . ,
| . ,
| . ,
| .
|
| ..(
| ,
| (, , , , )
| (
| .,
| .,
| .,
| .,
| .
|
| ))
|)
|
|
| .,
| .,
| .,
| .,
| .
|
|
| (.) < 0
|;
|///////////////////////////////////////////////////////////////////
|";
;
PS: , , .
( ), 1 ( ). 1 , .
SQL . , :
= ;
. =
"
| . ,
| . ,
| .
|
| .
| ..(., = .)
| . = .
| . = & "
;
= .();
2 : “ ” “ ”. - IN () ( 1, ), , , , , , — . SQL JOIN — LATERAL JOIN APPLY, 1 . , , , , . / . , .
, , , 1 , . 1 , , , . , (OLTP) , ( ), (, , , ).
1 SQL, SQL. , , SQL, 1 , .
( ). :
, , 1 (C, ), ( ). , 1 . - , , .
1 — SQL- 1 , . . , (MS SQL, Oracle), 1 PostgreSQL, « , ». ,
, PostgreSQL Join Predicate Push Down ( ). 1 , .
1 — ( , ). . ,
:
, - , ( , ). , .
1 « », . « » . . - , . ().
:
.,
.
..
..(,
(
..
= &))
. = .
. = &
(. < .
. NULL)
, , 1
, « » , , PostgreSQL, ( IN / EXISTS PostgreSQL ). , , , ( ).
SQL
, SQL 1 , , , . , - , CTE, 1 , . , , , , 1 , SQL- 1 SQL 92. , ,
( ), ORM, , , 1 .
, . , SQL, 1 ( DML), . , , ORM ( ) .
SQL ( CI ACID). ( ). , , , - , . , , , .
. , , . , , «» . (MVCC) Oracle PostgreSQL -, , .
, . , , , , ( , ), , . ? , ( ). , «» , :
- , . , , , , , SQL ( ), 1, .
- , , «» , FOR UPDATE ( ).
, , , ( ), , ( ).
1. ? . . ( ). . , . , - . — .
, «» 1 . , , / , , , .
ERP , , , . 1 . 1 Access, .
:
. - , , ( , ), . — ( -, ) , . ( ), — .
1? , , — . , , , — , , .. ( , ). :
. myForm otherForm, ( , ) .
, , 1 , , . / . :
- ( ). & 1 . , ( ), .
- «» ( Java EE) . , .
- ( , , windows ) , . ( )
, , . , 1 , . , (, ), ( ). - - , . . , , , , 1 () , , :
, , , 1 - .
? , , , ? , - , , . 1 - .
:
, . , , .
, - .
1 . , , - , . - :
&
()
= ("", );
();
&
(, )
();
&
()
= ("", );
= ("", , );
(, " ?", .);
&
(, )
= ?( = .,
" ...",
" !");
<> . <>
(., );
;
WYSIWYG:
/ WYSIWYG. , , , 1 , WYSIWYG , 1 .
1 . :
, , , ( ). 1 — , . , , , :
/
, , , . , / 1 , .
, , , :
. « » , .
, ( ) — 1 (, , ).
, , 1 , . , , , , , , .
1, , 1 , - . , , 1 , . :

: ? , , , , , 1, , .
- /
ORM. , ( ), , 1 , (), . , , 1 .
- /
, . , / C#, C++. . , , — . — - ( ), ( ) . , ( ORM, ORM) .
- /
( ) , . 1 - , (, ) (, ) . 1 , . , . , , ( ). , ( ).
, , , , . - .
1 , . , ( , ).
- / / (BI)
- : OLTP OLAP. - -: . OLAP — , «» , . OLTP , OLAP . , , OLTP - , , / , , -, ( ), -, - , . , , , ( OLAP), , .
OLAP , SQL - , . .
1 . () :
- , 1. (, ) . , , — .
1 - . , . , , , ( , , ), , ( ) , .
: OLAP , , ( , — _Fld16719 _Document5759).
1 , , 1.
, . 1, , 1 - SQL, SQL
, 1 .
, , «, , if'» . , 1, , , :
20 Foxpro ( IF TYPE(«tableA.fldB») = «C») , . , 2019 .
P.S.: 1
, .
1 . — (). , , ( , , 1 ). 1 , , . , ,
:
- , .
- , , , . , «» «» «» , :
.
.
.
. = .
- , .
- , , .
- , .
- .
, ( ). : « — ».
( , ..). . , , . IDE () - , , , , .
, , 1 . , -, , , , .
- . ( ) , , , , ( ), - , . .
1 . , -, , , . , ( ), 1 . , 1
:
, . -, , . -, , , , .
…
, .
-, — :
- , , , 1 ( -)
- , , N+1, , . 1 , (, ), , 1 .
- , , , 1
- , ,
, , , 1 . — . :
, 1 « SAP» — , : « , best practice, ». , , ( «--»). - . — . , , , :
- ( , / )
- ( : , , )
- . , ( , ), .
, low-code / no-code , . , / . — . / , . , / , , , . « , » , .
(--- vs ). , :
- — gitflow ( )
- / — / IDE
- — , , , « , » , ,
- — , , ..
- — IDE ( , , ..). .
- —
- — , / , , :
:
. , . , «», «» . , , «» , «» , ? , , .
1. , 1 EDT, « ». language-based, 1 , , XML.
. XML , :
- ( , ). ( ) 1336 .
- id, , , , .
/ — . ---, 1, . , , , .
, Microsoft 1, . , 1 , :
- IDE — IDEA, Eclipse, Microsoft Visual Studio / VSCode . IDEA , .
- — git , subversion mercurial . 1 git, , .
- — / , PostgreSQL, . , , 1 - SQL-92 , .
PostgreSQL, ( , 1 ), . .
- — , , . 1 - ( ) BI. 1 , .
- — 1 . , , , , ( -). language-based (, , SAP SQL, ), . 1 , . : « , , ». 1 - . , , , / — , , , callback' — .
- / — Jenkins TeamCity, Java — Maven, Gradle, JavaScript — npm, Python — pip .. community, , , IDE . 1 -, , , , , , .
- UI . , , Linux, MacOS ( Java ), , « » .
, 1 , Eclipse. , , , ( ERP) . , , Eclipse stub , (chameleon ), language injection .., IDEA ( Eclipse , , EDT ).
, EDT 1 IDE. ,
« ». , , Eclipse IDEA, 1 IDE.
1
. : 1: 8. 22 600 . (!). ? , : 1: 8 . 100 — 360 000. 1: 8.3 . — 86 400. , , (!) . , , , . , 22 600 . .
1 , , — 1 , ( ) — . , IT, : « / 1». , , : , — 1. — . , , , ( ) . :
- 1 , , , , - , ( ). : « 20 1 , ?». - , , ( ).
- , / 1 ( , , ..). , 1, - , , «1 », 1.
, IT- . , , . 1 , 1 . , , , , .
, , , 1 :
- ORM
- SQL:
- control flow
- WYSIWYG
, goto. . , «» . , , . — . , , — .
, , — , . , , . , ,
lsFusion , , ,
. .
, 1 , , (, , ) . , . , .
, : , . IT , ( ) Oracle, SAP Microsoft .
, 1 - . , . , — , , , « ». 1 , - ( «») — , , . lsFusion, , .Net+MSSQL Python+PostgreSQL . , , , . — ( , .Net) ? - : — , . IT. - ? , , , , , .
Axapta SAP. , ( 1 ), , , , , , . , , . , , , , , , , ( Axapta SAP , 1).