Pourquoi lsFusion et non 1C?





Article précédent "Pourquoi pas 1C?" est sorti il ​​y a plus d'un an et a suscité un vif intérêt (juste un peu moins de 100k vues et 2k commentaires). Cependant, comme prévu, de nombreuses questions raisonnables se sont posées: "Si ce n'est pas lui, alors qui?" Bien sûr, comme beaucoup l'ont compris, cet article n'a pas été écrit comme ça, mais pour en publier un autre après lui, où il serait dit comment les problèmes décrits dans le premier article peuvent et doivent être résolus. Cependant, pour diverses raisons, la publication de cet article de «réponse» a été retardée pendant très longtemps. Mais comme on dit, mieux vaut tard que jamais.







, ( ) lsFusion. , : (function-level, functional), , -, (constraint) . , buzzwords, , , .







« 1?» ( ):









1 , lsFusion.







: , ..



lsFusion , ( lsFusion — ). ( ). , , — , « ». , , :







  • , (, - , ), , , - (, / , ). , , «».
  • «» ( lsFusion / ), .




Puisque lsFusion essaie de tirer le meilleur parti du serveur SQL et non du serveur d'application pour exécuter la logique de calcul (et il le fait en regroupant le plus possible les requêtes afin de les exécuter le moins possible), l'opération de lecture d'un objet dans lsFusion n'existe pas en principe. En conséquence, le problème N + 1 et le problème de sur-lecture dans lsFusion sont extrêmement rares. Par exemple l'action suivante:





fillSum(Invoice i) {

    FOR invoice(InvoiceDetail id) = i DO

        sum(id) <- price(id) * quantity(id);

}





Il compilera en une seule étape:

fillSum(Invoice i) {

    sum(InvoiceDetail id) <- price(id) * quantity(id) WHERE invoice(id) = i

}





Qui, à son tour, sera exécuté avec une requête, dans laquelle seules les lignes / colonnes utilisées seront lues / écrites.



Tables / Vues: Registres



lsFusion , «» 1, , , , , « » ( , ), . , lsFusion :







  • — , (, )
  • / — , , :
    • — GROUP LAST
    • , — SUM ( lsFusion , lsFusion , )


lsFusion , .







, . lsFusion , , . - :





LEDGER Sales GROUP Stock stock, Sku sku SUM NUMERIC quantity, NUMERIC sum;



//    Sales   :

// stock, sku, quantity, sum = ABSTRACT Stock, Sku, NUMERIC, NUMERIC (Sales); - 

  / 

// quantitySales, sumSales (stock, sku) -   ( =   +  )

// quantitySales, sumSales (stock, sku, DATETIME) -    

// quantitySales, sumSales (stock, sku, DATETIME, DATETIME) -     

//  ..





Et dans les prochaines versions, un tel sucre syntaxique apparaîtra très probablement. Une autre chose est que le plus souvent dans les projets complexes, les registres ont une structure plus complexe (par exemple, ils héritent les uns des autres, dénormalisent les données pour les indices composites, se développent dans différents modules, etc.), de sorte qu'un tel sucre ne peut être important que pour Développement RAD (et plus précisément prototypage), qui n'est plus aussi pertinent dans le monde informatique moderne.



Les registres sont pris en charge dans des cas très particuliers



Comme mentionné ci-dessus, les registres dans lsFusion ne sont pas une grande combinaison, mais plusieurs mécanismes différents, dont la clé est peut-être le mécanisme de matérialisation (enregistrement et mise à jour automatique des données calculées dans des tableaux).







1, lsFusion , . , lsFusion :







  1. , , , ( " ").
  2. / / , .
  3. , , , “” ( ).
  4. (), .




lsFusion prend en charge les contraintes et les événements en général, y compris les données non matérialisées calculées. Ainsi, par exemple, pour créer une contrainte que le reste (qui peut être calculé en utilisant n'importe quel nombre de données / opérateurs différents) doit être supérieur à 0, il suffit d'écrire une seule ligne:





CONSTRAINT currentBalance(sku, stock) < 0 MESSAGE '    ';





En conséquence, la plateforme vérifiera elle-même le plus efficacement possible (à l'aide de calculs incrémentiels) qu'aucune modification (par exemple, un changement dans l'entrepôt de la réception ou le montant de la consommation) ne violera cette limitation.

De la même manière, vous pouvez également créer, par exemple, des notifications sur les modifications de toute donnée, y compris calculée:





WHEN SET(currentBalance(Sku sku, Stock stock) < 0//     0

    EMAIL SUBJECT '   ' + address(stock) + '   ' + name(sku) + 

'   0' TO responsibleEmail(group(sku));





Seules les constantes peuvent être utilisées dans les paramètres de table virtuelle



- lsFusion . , , , , . , , , lsFusion . :





EXPORT FROM price(Sku sku), balance(date(sku), sku) WHERE name(sku) = '';





La plate-forme poussera automatiquement la condition de nom contraignant (et en conséquence de la date à laquelle le reste sera calculé) dans la sous-requête (et toutes les sous-requêtes à l'intérieur de cette sous-requête), effectuant ainsi l'optimisation de la poussée vers le bas du prédicat . De plus, contrairement au même SQL, la plateforme est capable d'effectuer cette optimisation non seulement pour les regroupements, mais aussi pour les partitions et même pour les récursions. Cependant, c'est un sujet pour un article séparé, nous ne nous attarderons pas dessus en détail ici.



Demandes de renseignements



, lsFusion SQL ( ), , . , , .









lsFusion, :







  • IDE — , , , ..
  • IDE ( ), , .


, / (IF, SHOWIF ..), (EVAL), lsFusion.









LsFusion dispose d'un moteur d'optimisation des requêtes très puissant en interne, effectuant dans de nombreux cas des optimisations que même les SGBD commerciaux coûteux (sans parler de PostgreSQL) ne peuvent pas faire. Ainsi, tous les problèmes de performances décrits dans l'article "Pourquoi pas SQL" , lsFusion est capable de les résoudre de manière indépendante sans aucune action supplémentaire de la part du développeur, qui, par conséquent, peut se concentrer sur la résolution des problèmes commerciaux, et ne pas réfléchir à la façon de écrire correctement une requête et / ou dans quelle table temporaire mettre son résultat.







Ainsi, un exemple d'un article sur 1C dans lsFusion ressemblera à ceci:







Exemple de l'article

    .,
    .

    ..  
          ..(,
                               (
                                    
                                    ..
                                     = &))  
         . = .

    . = & 
    (. < . 
        .  NULL)
      
      



currentBalance(InvoiceDetail id) = currentBalance(sku(id));



export(Invoice i) {

    EXPORT FROM sku(InvoiceDetail id), currentBalance(id) WHERE invoice(id) = i AND 

currentBalance(id) < quantity(id) OR NOT currentBalance(id);

}





Par conséquent, aucune "Nomenclature IN (SELECT Nomenclature FROM Document.Invoice.Content WHERE Reference = & Document)" dans lsFusion n'a pas besoin d'être écrite.



SQL



SQL-92, ( SQL — ), lsFusion :







  • / ( SQL — )
  • ( SQL — CTE)
  • ( SQL — )


lsFusion - ( GROUP BY ).









ERP- ORM , , - , ERP- SQL- .







Cependant, dans le même 1C, les requêtes ne sont prises en charge que pour les opérations de lecture de données; pour l'écriture, vous devez toujours utiliser des mécanismes ORM, dont les performances laissent beaucoup à désirer. Dans lsFusion, ce problème n'existe pas et toutes les opérations, y compris la création d'objets, peuvent être effectuées sur le serveur de base de données, et avec une seule requête. Par exemple:





generateCards() {

    FOR iterate(i,1,10000NEW d = DiscountCard DO

            number(d) ← ‘Card:’+i;

}







Au final, il sera compilé en une seule requête (ou plusieurs, mais leur nombre ne dépendra pas de la quantité de données) et sera exécuté très rapidement, et tous les événements / contraintes / agrégations seront également exécutés / vérifiés / recalculés par un nombre limité nombre de demandes (encore une fois, indépendant de la quantité de données).

Il en va de même pour le mécanisme de modification / suppression d'une grande quantité de données / objets:





FOR sum(DiscountCard d) > 10000 DO

    vip (d) ← TRUE;

FOR sum(DiscountCard d) > 10000 DO

    DELETE d;





Compilera pour:

sum(DiscountCard d) ← TRUE  WHERE sum(d) > 10000;

DELETE DiscountCard d WHERE sum(d) > 10000;





Et encore une fois, il sera exécuté en une seule requête.





( ) 1, . :







  1. ( MS SQL).
  2. Repeatable Read Serializable.
  3. , .
  4. .


lsFusion. , 1 ( ) lsFusion:







  • , ( , ),
  • , , « ».




lsFusion — , / .







:



Contrairement à 1C dans lsFusion, le flux d'exécution est le même pour le serveur et le client. Cette unité simplifie grandement l'interaction avec le dispositif utilisateur / client en termes de processus de développement. Ainsi, l'exemple de l'article sur 1C est écrit dans le langage lsFusion et ressemble donc à ceci:





f() <- someData(); //       myForm

DIALOG myForm OBJECTS a INPUT DO // , 

 - 

     IF isSomething(a) DO //          - 

 

         DIALOG otherForm OBJECTS b = a DO { // ,  

       b

             g(b) <- someInput(b); //    b

             APPLY//    

         }





Dans une certaine mesure, lsFusion utilise l'approche des formulaires conventionnels en 1C, mais cela le rend beaucoup plus évolutif et productif. En fait, toute la magie de l'asynchronie reste sous le capot, et le développeur peut se concentrer strictement sur la résolution des problèmes commerciaux, et ne pas penser à où et comment le code qu'il écrit doit s'exécuter.

, lsFusion ( /). , lsFusion CLIENT INTERNAL, . Java, - — JavaScript. “ ” , .









- ( ) “” ( , , ). (, ), , , 1 ( , async / await, ).







lsFusion , , , , .







WYSIWYG:



, 1 , ( ), 2 :







  • - , / ().
  • .


1 . lsFusion , , , «Excel-style» , , , , , . ( lsFusion) « » — / . , .







/



Dans lsFusion, lorsque vous définissez des propriétés, des filtres et d'autres éléments sur un formulaire, vous pouvez accéder à tous les objets à la fois, même s'ils apparaissent dans différentes listes (ou d'autres vues). Dans le même temps, la plate-forme elle-même surveille les modifications des objets (ainsi que les modifications des données) et met à jour automatiquement les données de formulaire à l'aide de ces objets. Par exemple, si vous créez le formulaire suivant:





FORM balance

    OBJECTS st = Stock, sk = Sku

    PROPERTIES (st) name

    PROPERTIES name(sk), currentBalance(st, sk)

    FILTERS currentBalance(st, sk)

;





Lorsque vous déplacez l'enregistrement actuel dans la liste supérieure (entrepôts), la liste inférieure (produits qui se trouvent dans l'entrepôt sélectionné) sera mise à jour automatiquement.



Niveaux d'abstraction redondants



Le principe principal lors de la création de lsFusion était et reste le principe - la pureté et l'exhaustivité de toutes les abstractions créées. Alors:







  • lsFusion . — . , .
  • ( ) , , , ( ).
    :




, lsFusion 1. 1 lsFusion:







  • /


lsFusion ( ) . , ( , ..) , «» ( ).







  • /


, 1 - lsFusion ( , ).







  • /


lsFusion , . - « » lsFusion . , . - , , ( ). lsFusion .







  • / / (BI)


. , / lsFusion ( ). , ( , ) lsFusion :







  • , JasperReports, Java. pixel-perfect , .
  • , , , .

  • — «» , , « » ( ).
  • , ( ) JSON, XML, XLSX, DBF .


lsFusion — . , , . , , / .









lsFusion , lsFusion , / ( 1). lsFusion — , . , , , ( ). - .







:







  1. ( BI).
  2. (, )
  3. .




PS: « » ( ) « 1?» , , , , . , , .







Comme mentionné dans la section précédente, le mappage de la logique de données dans lsFusion à une base de données relationnelle est transparent et peut être entièrement contrôlé par le développeur. Avec les matérialisations en général et les index, un développeur (et même un administrateur) peut atteindre presque toutes les performances, même sur d'énormes quantités de données. De plus, étant donné que la plate-forme elle-même surveille les modifications du modèle physique et met à jour la structure de la base de données sans aucune migration supplémentaire, le processus d'optimisation des performances peut (et doit) être effectué sur une base de données en cours d'exécution lorsque les statistiques et les options d'utilisation de cette base de données sont connues. Alors disons que nous avons un exemple simple:





date = DATA DATE (DocumentDetail)

barcode = DATA STRING (Sku);

sku = DATA Sku (DocumentDetail); 



barcode(DocumentDetail dd) = barcode(sku(dd));

count (STRING bc, DATE d) = GROUP SUM 1 IF date(DocumentDetail dd) > d AND barcode(dd) = bc;

FORM x

        OBJECTS bc = STRING PANEL, d = DATE PANEL

        PROPERTIES count(bc, d), VALUE (bc), VALUE(d)

;





Lors de l'exécution de ce formulaire, une requête sera générée dans laquelle elle sera:

  1. JOIN avec la table des produits, le code-barres dans la table SKU correspond à celui spécifié;
  2. compter le nombre de lignes de document pour toutes les dates supérieures à celle spécifiée.


Dans ce cas, le serveur SQL aura deux options: soit exécuté par l'index par dates dans le tableau des lignes, soit par l'index par codes-barres dans la table des marchandises, rechercher des marchandises, puis exécuté par l'index par Sku dans le tableau des lignes. Dans les deux cas, la performance laissera beaucoup à désirer (s'il y a beaucoup de mouvements d'un produit et beaucoup de produits). Dans lsFusion, pour résoudre ce problème, il suffit de modifier / ajouter les lignes suivantes:





barcode(DocumentDetail dd) = barcode(sku(d)) MATERIALIZED// ,  

   

INDEX barcode(DocumentDetail dd), date(dd);//   





Après une telle optimisation, le serveur SQL pourra commencer à utiliser l'index composite construit et les performances seront maximales.



Sources fermées et licences



- . Microsoft, , .Net, Linux.







, , — ERP-, , : — . , .







lsFusion LGPL v3 , , ( ), . GitHub. Maven-, Maven: compile, install, package .. , , GitHub Projects. , .









. lsFusion . , ( ), ( ).







( ), , ( ).







lsFusion , tutorial, , .









lsFusion . ( ), . , ( ) .







, , , , , . :





invoice (InvoiceDetail id) = DATA Invoice;

sum = GROUP SUM sum(InvoiceDetail id) BY invoice(id) //  sum   

  Invoice (    invoce,    - Invoice)



FORM myForm

    OBJECTS myObject = MyClass

;

filtered = FILTER myForm.myObject ; //  filtered      

MyClass (    myObject  myForm)









, , - , custom-made . , , . , / «», .







lsFusion . :







  1. ( , — ) — - . , , , , / .
  2. — . - - (, ).
  3. — , ( ). , - ( «» / , ).
  4. , ( ). , this, , lsFusion , - «».
  5. — , , - ( )


, , , lsFusion ( ), lsFusion / , .







, «» lsFusion — ( ) , , . ( , ), ( ).









, , Everything as code . lsFusion.







, , lsFusion . , , ( ). lsFusion IDEA : , , , .. -, , .









, , , — 1, ERP-. , , , :







  1. .
  2. , , , .


lsFusion : - , - . - , .







, lsFusion:
  1. . “ - ”. Java . , 1, lsFusion . , , , . , . . , .







    , lsFusion — lsFusion ANTLR, IDEA Grammar-Kit (), JFlex ().





  2. UI. - Java SE (Swing, Web Start), , . , , -, - .







    - lsFusion :





    • GWT — Java (), . , , , , GWT , . GWT JavaScript, JavaScript







      , GWT , TypeScript . :







      ) - TypeScript - ;







      ) lsFusion GWT , , .







      - TypeScript, , .





    • Full Calendar, Leaflet — “” ( ).
    • Spring Security, MVC, DI — , , (, ).
  3. BI — “” lsFusion “ ”. :





    • pivot-table, subtotal — BI, ( ),
    • plotly — ,
    • tableToExcel — Excel ( , collapsible ..).


    , ( , ), open-source, - — .





  4. . lsFusion — JasperReports.







    . 1 , , , , :







    ) , , , 4 ;







    ) “”, pixel-perfect .







    lsFusion : ( renderer’, , . .), . BI ( , . .), ( ).





  5. IDE. IDE, IDEA (Eclipse ), IDEA . , , IDEA , . IDEA ( IntelliJ Platform) IDE, , lsFusion ( , lsFusion ). stub index’, chameleon element' lsFusion (, , ).
  6. . Everything as code , , , Git. , Subversion (, , ).
  7. / . EaC / Java, Maven ( lsFusion repo.lsfusion.org).







    Maven- pom.xml :







    <repositories>
            <repository>
                <id>lsfusion</id>
                <name>lsFusion Public Repository</name>
                <url>http://repo.lsfusion.org</url>
            </repository>
    </repositories>
    
          
          





    , Maven Java . , , Maven , pom.xml.







    <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-math3</artifactId>
            <version>3.2</version>
    </dependency>
    
          
          





    IDE, .





  8. . JDBC, / . Postgres ( Docker, yum ..)







    Java Spring, .











, lsFusion LGPL v3.0, , , , lsFusion . , lsFusion , , . , lsFusion , , , , / , . -? , «-» , , , — , -. , ( , , «as is», «to be»). , , , «», , :







  • — , , . «», — .
  • ,


, lsFusion (- / lsFusion, ), (, , ).







, , . , , / , , , .







. , ( - ), ( / ). ( IT) , , , ( ). MyCompany. , , , , , , .









, , - — . , . , , , :







  1. - ( ), , / . .
  2. , , , ( , , ). , , , , . , 30 3000 , - .


, , . , lsFusion , 1 ERP-.







, :

«» ( )



( , ) , / .









( ), , , - . . . .







( Google docs)



, ( , , , ).









, ( ). , .









1, , . ( ), , , , , ( ). , :







  1. , .
  2. , , , « » ( , ).


/



:







  • — , drag-drop .
  • — WYSIWYG , - ( ).
  • — > ( -> , ).
  • , — ( )


, ( -).







/



1 :







  • — , (, , Odoo lsFusion)
  • — renderer, / , , , «» js- ( , ).


( )



, :







  • ( )
  • ( / )
  • ..


1 «-» , 1 / , , .









, « 1», — - 1 lsFusion ( , ). , 1- , .










All Articles