Hızlı Uygulama Geliştirme Çerçevesi ile Uygulama Geliştirme AllcountJS

Yayınlanan: 2022-03-11

Hızlı Uygulama Geliştirme (RAD) fikri, geleneksel şelale geliştirme modellerine yanıt olarak doğdu. RAD'nin birçok varyasyonu mevcuttur; örneğin, Çevik geliştirme ve Rational Unified Process. Bununla birlikte, bu tür tüm modellerin ortak bir yanı vardır: prototipleme ve yinelemeli geliştirme yoluyla minimum geliştirme süresiyle maksimum iş değeri elde etmeyi amaçlarlar. Bunu başarmak için Hızlı Uygulama Geliştirme modeli, süreci kolaylaştıran araçlara dayanır. Bu makalede, böyle bir aracı ve geliştirme sürecinin iş değerine ve optimizasyonuna odaklanmak için nasıl kullanılabileceğini keşfedeceğiz.

AllcountJS, hızlı uygulama geliştirme göz önünde bulundurularak oluşturulmuş, gelişmekte olan bir açık kaynak çerçevesidir. Uygulamanın yapısını ve davranışını tanımlayan JSON benzeri yapılandırma kodunu kullanarak bildirime dayalı uygulama geliştirme fikrine dayanır. Çerçeve Node.js, Express, MongoDB üzerine inşa edilmiştir ve ağırlıklı olarak AngularJS ve Twitter Bootstrap'a dayanmaktadır. Bildirimsel kalıplara bağlı olmasına rağmen, çerçeve gerektiğinde API'ye doğrudan erişim yoluyla daha fazla özelleştirmeye izin verir.

RAD Çerçeveniz olarak AllcountJS

Neden RAD Çerçeveniz Olarak AllcountJS?

Wikipedia'ya göre, hızlı uygulama geliştirmeyi vaat eden en az yüz araç var, ancak bu şu soruyu gündeme getiriyor: "Hızlı" ne kadar hızlı. Bu araçlar, belirli bir veri merkezli uygulamanın birkaç saat içinde geliştirilmesine izin veriyor mu? Ya da uygulama birkaç gün veya birkaç hafta içinde geliştirilebilirse belki de “hızlı” olur. Bu araçlardan bazıları, çalışan bir uygulama oluşturmak için birkaç dakikanın yeterli olduğunu bile iddia ediyor. Ancak, beş dakikadan daha kısa bir sürede yararlı bir uygulama oluşturup yine de tüm iş ihtiyaçlarını karşıladığınızı iddia etmeniz pek olası değildir. AllcountJS böyle bir araç olduğunu iddia etmez; AllcountJS'in sunduğu şey, bir fikri kısa sürede prototiplemenin bir yoludur.

AllcountJS çerçevesi ile, temaya uygun, otomatik olarak oluşturulmuş bir kullanıcı arayüzü, kullanıcı yönetimi özellikleri, RESTful API ve bir dizi başka özellik ile minimum çaba ve zaman ile bir uygulama oluşturmak mümkündür. AllcountJS'yi çok çeşitli kullanım durumları için kullanmak mümkündür, ancak onlar için farklı görünümlere sahip farklı nesne koleksiyonlarına sahip olduğunuz uygulamalara en uygunudur. Tipik olarak, iş uygulamaları bu model için uygundur.

AllcountJS, allcountjs.com'u ve bunun için bir proje izleyicisini oluşturmak için kullanıldı. allcountjs.com'un özelleştirilmiş bir AllcountJS uygulaması olduğunu ve AllcountJS'nin hem statik hem de dinamik görünümlerin çok az güçlükle birleştirilmesine izin verdiğini belirtmekte fayda var. Dinamik olarak yüklenen parçaların statik içeriğe eklenmesine bile izin verir. Örneğin, AllcountJS bir demo uygulama şablonları koleksiyonunu yönetir. allcountjs.com'un ana sayfasında, o koleksiyondan rastgele bir uygulama şablonu yükleyen bir demo widget'ı var. allcountjs.com adresindeki galeride bir avuç başka örnek uygulama mevcuttur.

Başlarken

RAD çerçevesi AllcountJS'nin bazı yeteneklerini göstermek için Toptal için Toptal Topluluğu adını vereceğimiz basit bir uygulama oluşturacağız. Blogumuzu takip ediyorsanız, daha önceki blog yazılarımızdan birinin parçası olarak Hoodie kullanılarak benzer bir uygulamanın oluşturulduğunu zaten biliyor olabilirsiniz. Bu uygulama, topluluk üyelerinin kaydolmasına, etkinlikler oluşturmasına ve bunlara katılmak için başvurmasına olanak tanır.

Ortamı kurmak için Node.js, MongoDB ve Git kurmalısınız. Ardından, bir “npm install” komutunu çağırarak AllcountJS CLI'yi kurun ve proje başlatma işlemini gerçekleştirin:

 npm install -g allcountjs-cli allcountjs init toptal-community-allcount cd toptal-community-allcount npm install

AllcountJS CLI, package.json dosyasını önceden doldurmak için projeniz hakkında bazı bilgiler girmenizi isteyecektir.

AllcountJS, bağımsız sunucu veya bağımlılık olarak kullanılabilir. İlk örneğimizde AllcountJS'yi genişletmeyeceğiz, bu nedenle bağımsız bir sunucu bizim için çalışmalıdır.

Bu yeni oluşturulan app-config dizini içinde, main.js JavaScript dosyasının içeriğini aşağıdaki kod parçasıyla değiştireceğiz:

 A.app({ appName: "Toptal Community", onlyAuthenticated: true, allowSignUp: true, appIcon: "rocket", menuItems: [{ name: "Events", entityTypeId: "Event", icon: "calendar" }, { name: "My Events", entityTypeId: "MyEvent", icon: "calendar" }], entities: function(Fields) { return { Event: { title: "Events", fields: { eventName: Fields.text("Event").required(), date: Fields.date("Date").required(), time: Fields.text("Starts at").masked("99:99").required(), appliedUsers: Fields.relation("Applied users", "AppliedUser", "event") }, referenceName: "eventName", sorting: [['date', -1], ['time', -1]], actions: [{ id: "apply", name: "Apply", actionTarget: 'single-item', perform: function (User, Actions, Crud) { return Crud.actionContextCrud().readEntity(Actions.selectedEntityId()).then(function (eventToApply) { var userEventCrud = Crud.crudForEntityType('UserEvent'); return userEventCrud.find({filtering: {"user": User.id, "event": eventToApply.id}}).then(function (events) { if (events.length) { return Actions.modalResult("Can't apply to event", "You've already applied to this event"); } else { return userEventCrud.createEntity({ user: {id: User.id}, event: {id: eventToApply.id}, date: eventToApply.date, time: eventToApply.time }).then(function () { return Actions.navigateToEntityTypeResult("MyEvent") }); } }); }) } }] }, UserEvent: { fields: { user: Fields.fixedReference("User", "OnlyNameUser").required(), event: Fields.fixedReference("Event", "Event").required(), date: Fields.date("Date").required(), time: Fields.text("Starts at").masked("99:99").required() }, filtering: function (User) { return {"user.id": User.id} }, sorting: [['date', -1], ['time', -1]], views: { MyEvent: { title: "My Events", showInGrid: ['event', 'date', 'time'], permissions: { write: [], delete: null } }, AppliedUser: { permissions: { write: [] }, showInGrid: ['user'] } } }, User: { views: { OnlyNameUser: { permissions: { read: null, write: ['admin'] } }, fields: { username: Fields.text("User name") } } } } } });

AllcountJS Git depolarıyla çalışsa da, basitlik adına onu bu eğitimde kullanmayacağız. Toptal Community uygulamasını çalıştırmak için tek yapmamız gereken toptal-community-allcount dizininde AllcountJS CLI run komutunu çağırmak.

 allcountjs run

Bu komut yürütüldüğünde MongoDB'nin çalışıyor olması gerektiğini belirtmekte fayda var. Her şey yolunda giderse, uygulama http://localhost:9080 adresinde çalışır durumda olmalıdır.

Giriş yapmak için lütfen "admin" kullanıcı adını ve "admin" şifresini kullanın.

100 Satırdan Az

main.js'de tanımlanan uygulamanın sadece 91 satır kod aldığını fark etmişsinizdir. Bu satırlar, http://localhost:9080'e gittiğinizde gözlemleyebileceğiniz tüm davranışların bildirimini içerir. Peki, kaputun altında tam olarak ne oluyor? Uygulamanın her yönüne daha yakından bakalım ve kodun bunlarla nasıl ilişkili olduğunu görelim.

Giriş yap Kayıt Ol

Uygulamayı açtıktan sonra gördüğünüz ilk sayfa bir oturum açma sayfasıdır. Bu, formu göndermeden önce “Kaydol” etiketli onay kutusunun işaretli olduğu varsayıldığında, bir kayıt sayfası olarak ikiye katlanır.

Giriş yap Kayıt Ol

Bu sayfa, main.js dosyası yalnızca kimliği doğrulanmış kullanıcıların bu uygulamayı kullanabileceğini bildirdiği için gösterilmektedir. Ayrıca, kullanıcıların bu sayfadan kaydolmalarını sağlar. Aşağıdaki iki satır bunun için gerekliydi:

 A.app({ ..., onlyAuthenticated: true, allowSignUp: true, ... })

Sayfaya hoşgeldiniz

Oturum açtıktan sonra, uygulama menüsü içeren bir karşılama sayfasına yönlendirileceksiniz. Uygulamanın bu kısmı, “menuItems” tuşu altında tanımlanan menü öğelerine dayalı olarak otomatik olarak oluşturulur.

hoş geldiniz sayfası örneği

Birkaç diğer ilgili konfigürasyonla birlikte menü, main.js dosyasında aşağıdaki gibi tanımlanır:

 A.app({ ..., appName: "Toptal Community", appIcon: "rocket", menuItems: [{ name: "Events", entityTypeId: "Event", icon: "calendar" }, { name: "My Events", entityTypeId: "MyEvent", icon: "calendar" }], ... });

AllcountJS, Font Awesome simgelerini kullanır, bu nedenle yapılandırmada başvurulan tüm simge adları, Font Awesome simge adlarıyla eşlenir.

Etkinliklere Göz Atma ve Düzenleme

Menüden “Etkinlikler”e tıkladıktan sonra, aşağıdaki ekran görüntüsünde gösterilen Etkinlikler görünümüne yönlendirileceksiniz. Karşılık gelen varlıklar üzerinde bazı genel CRUD işlevleri sağlayan standart bir AllcountJS görünümüdür. Burada etkinlik arayabilir, yeni etkinlikler oluşturabilir ve mevcut etkinlikleri düzenleyebilir veya silebilirsiniz. Bu CRUD arayüzünün iki modu vardır: liste ve form. Uygulamanın bu kısmı, aşağıdaki birkaç JavaScript kodu satırı aracılığıyla yapılandırılır.

 A.app({ ..., entities: function(Fields) { return { Event: { title: "Events", fields: { eventName: Fields.text("Event").required(), date: Fields.date("Date").required(), time: Fields.text("Starts at").masked("99:99").required(), appliedUsers: Fields.relation("Applied users", "AppliedUser", "event") }, referenceName: "eventName", sorting: [['date', -1], ['time', -1]], ... } } } });

Bu örnek, varlık tanımlarının AllcountJS'de nasıl yapılandırıldığını gösterir. Varlıkları tanımlamak için bir işlevi nasıl kullandığımıza dikkat edin; AllcountJS konfigürasyonunun her özelliği bir fonksiyon olabilir. Bu işlevler, bağımsız değişken adları aracılığıyla çözülecek bağımlılıkları talep edebilir. Fonksiyon çağrılmadan önce uygun bağımlılıklar enjekte edilir. Burada "Alanlar", varlık alanlarını tanımlamak için kullanılan AllcountJS yapılandırma API'lerinden biridir. "Varlıklar" özelliği, adın bir varlık türü tanımlayıcısı ve değerin de açıklaması olduğu ad-değer çiftlerini içerir. Bu örnekte, başlığın "Olaylar" olduğu, olaylar için bir varlık türü açıklanmıştır. Varsayılan sıralama, referans adı ve benzerleri gibi diğer konfigürasyonlar da burada tanımlanabilir. Varsayılan sıralama düzeni, bir dizi alan adı ve yön aracılığıyla tanımlanırken, referans adı bir dize aracılığıyla tanımlanır (daha fazlasını buradan okuyun).

allcountJS işlevi

Bu özel varlık türü, dört alana sahip olarak tanımlanmıştır: "eventName", "date", "time" ve "appliedUsers", bunlardan ilk üçü veritabanında kalıcıdır. Bu alanlar, "required()" kullanımıyla belirtildiği gibi zorunludur. Bu tür kurallara sahip bu alanlardaki değerler, aşağıdaki ekran görüntüsünde gösterildiği gibi, form ön uçta gönderilmeden önce doğrulanır. AllcountJS, en iyi kullanıcı deneyimini sağlamak için hem istemci tarafı hem de sunucu tarafı doğrulamalarını birleştirir. Dördüncü alan, etkinliğe katılmak için başvuran kullanıcıların listesini taşıyan bir ilişkidir. Doğal olarak, bu alan veritabanında kalıcı değildir ve yalnızca olayla ilgili AppliedUser varlıkları seçilerek doldurulur.

allcountjs geliştirme kuralları

Etkinliklere Katılmak İçin Başvuru

Bir kullanıcı belirli bir olayı seçtiğinde, araç çubuğunda "Uygula" etiketli bir düğme gösterilir. Üzerine tıklamak, olayı kullanıcının programına ekler. AllcountJS'de buna benzer eylemler, yapılandırmada basitçe bildirilerek yapılandırılabilir:

 actions: [{ id: "apply", name: "Apply", actionTarget: 'single-item', perform: function (User, Actions, Crud) { return Crud.actionContextCrud().readEntity(Actions.selectedEntityId()).then(function (eventToApply) { var userEventCrud = Crud.crudForEntityType('UserEvent'); return userEventCrud.find({filtering: {"user": User.id, "event": eventToApply.id}}).then(function (events) { if (events.length) { return Actions.modalResult("Can't apply to event", "You've already applied to this event"); } else { return userEventCrud.createEntity({ user: {id: User.id}, event: {id: eventToApply.id}, date: eventToApply.date, time: eventToApply.time }).then(function () { return Actions.navigateToEntityTypeResult("MyEvent") }); } }); }) } }]

Herhangi bir varlık türünün "eylemleri" özelliği, her özel eylemin davranışını tanımlayan bir dizi nesne alır. Her nesnenin eylem için benzersiz bir tanımlayıcı tanımlayan bir "id" özelliği vardır, "name" özelliği görünen adı tanımlar ve "actionTarget" özelliği eylem bağlamını tanımlamak için kullanılır. "actionTarget"ın "tek öğe" olarak ayarlanması, eylemin belirli bir olayla gerçekleştirilmesi gerektiğini belirtir. "Perform" özelliği altında tanımlanan bir işlev, bu eylem gerçekleştirildiğinde, tipik olarak kullanıcı ilgili düğmeye tıkladığında yürütülen mantıktır.

Bu fonksiyon tarafından bağımlılıklar talep edilebilir. Örneğin, bu örnekte işlev "Kullanıcı", "Eylemler" ve "Hata"ya bağlıdır. Bir eylem gerçekleştiğinde, bu eylemi çağıran kullanıcıya bir referans, “Kullanıcı” bağımlılığı istenerek elde edilebilir. Bu varlıklar için veritabanı durumunun manipülasyonuna izin veren “Crud” bağımlılığı da burada talep edilmektedir. Bir Crud nesnesi örneği döndüren iki yöntem şunlardır: “actionContextCrud()” yöntemi - “Uygula” eylemi kendisine ait olduğundan “Event” varlık türü için CRUD döndürürken “crudForEntityType()” yöntemi - CRUD döndürür tür kimliğiyle tanımlanan herhangi bir varlık türü için.

CRUD bağımlılıkları

Eylemin uygulanması, bu olayın kullanıcı için önceden planlanıp planlanmadığını kontrol ederek başlar ve değilse, bir tane oluşturur. Zaten programlanmışsa, “Actions.modalResult()” çağrısından gelen değer döndürülerek bir iletişim kutusu gösterilir. Bir eylem, bir kip göstermenin yanı sıra, "görünüşe git", "görünümü yenile", "iletişim kutusunu göster" gibi farklı türde işlemleri benzer şekilde gerçekleştirebilir.

eylemin uygulanması

Uygulanan Olayların Kullanıcı Takvimi

Bir etkinliğe başarıyla uygulandıktan sonra tarayıcı, kullanıcının başvurduğu etkinliklerin listesini gösteren "Olaylarım" görünümüne yönlendirilir. Görünüm, aşağıdaki yapılandırma ile tanımlanır:

 UserEvent: { fields: { user: Fields.fixedReference("User", "OnlyNameUser").required(), event: Fields.fixedReference("Event", "Event").required(), date: Fields.date("Date").required(), time: Fields.text("Starts at").masked("99:99").required() }, filtering: function (User) { return {"user.id": User.id} }, sorting: [['date', -1], ['time', -1]], views: { MyEvent: { title: "My Events", showInGrid: ['event', 'date', 'time'], permissions: { write: [], delete: null } }, AppliedUser: { permissions: { write: [] }, showInGrid: ['user'] } } },

Bu durumda, "filtreleme" adlı yeni bir yapılandırma özelliği kullanıyoruz. Önceki örneğimizde olduğu gibi, bu işlev de “Kullanıcı” bağımlılığına dayanır. İşlev bir nesne döndürürse, bir MongoDB sorgusu olarak kabul edilir; sorgu, yalnızca geçerli kullanıcıya ait olaylar için koleksiyonu filtreler.

Bir başka ilginç özellik de “Görünümler”. “Görünüm” normal bir varlık türüdür, ancak MongoDB koleksiyonu ana varlık türüyle aynıdır. Bu, veritabanındaki aynı veriler için görsel olarak farklı görünümler oluşturmayı mümkün kılar. Aslında bu özelliği “UserEvent” için iki farklı görünüm oluşturmak için kullandık: “MyEvent” ve “AppliedUser”. Alt görünümlerin prototipi üst varlık tipine ayarlandığından, geçersiz kılınmayan özellikler üst türden "devralınır".

Görüntüleme

Etkinlik Katılımcılarını Listeleme

Bir etkinliğe başvurduktan sonra, diğer kullanıcılar katılmayı planlayan tüm kullanıcıların bir listesini görebilir. Bu, main.js'deki aşağıdaki yapılandırma öğelerinin bir sonucu olarak oluşturulur:

 AppliedUser: { permissions: { write: [] }, showInGrid: ['user'] } // ... appliedUsers: Fields.relation("Applied users", "AppliedUser", "event")

"AppliedUser", bir "MyEvent" varlık türü için salt okunur bir görünümdür. Bu salt okunur izin, izinler nesnesinin "Write" özelliğine boş bir dizi ayarlanarak uygulanır. Ayrıca, “Okuma” izni tanımlanmadığından, varsayılan olarak tüm kullanıcılar için okumaya izin verilir.

myevent tipi için applicationuser

Varsayılan Uygulamaları Genişletme

RAD çerçevelerinin tipik arka planı, esneklik eksikliğidir. Uygulamanızı oluşturduktan ve özelleştirmeniz gerektiğinde, önemli engellerle karşılaşabilirsiniz. AllcountJS, genişletilebilirlik düşünülerek geliştirilmiştir ve içerideki her yapı taşının değiştirilmesine izin verir.

Bunu başarmak için AllcountJS kendi Bağımlılık Ekleme (DI) uygulamasını kullanır. DI, geliştiricinin çerçevenin varsayılan davranışlarını uzatma noktaları aracılığıyla geçersiz kılmasına ve aynı zamanda mevcut uygulamaların yeniden kullanılmasına izin verir. RAD çerçeve uzantısının birçok yönü belgelerde açıklanmıştır. Bu bölümde, çerçevedeki birçok bileşenden ikisini, sunucu tarafı mantığı ve görünümleri nasıl genişletebileceğimizi keşfedeceğiz.

Toptal Topluluğu örneğimizle devam ederek, etkinlik verilerini toplamak için harici bir veri kaynağını entegre edelim. Her etkinlikten bir gün önce etkinlik planlarını tartışan Toptal Blog gönderileri olduğunu düşünelim. Node.js ile blogun RSS beslemesini ayrıştırmak ve bu tür verileri çıkarmak mümkün olmalıdır. Bunu yapmak için, "request", "xml2js" (Toptal Blog RSS beslemesini yüklemek için), "q" (sözlerini uygulamak için) ve "moment" (tarihleri ​​ayrıştırmak için) gibi bazı ekstra npm bağımlılıklarına ihtiyacımız olacak. Bu bağımlılıklar, aşağıdaki komut kümesi çağrılarak kurulabilir:

 npm install xml2js npm install request npm install q npm install moment

Başka bir JavaScript dosyası oluşturalım, onu toptal-community-allcount dizininde “toptal-community.js” olarak adlandıralım ve onu aşağıdakilerle dolduralım:

 var request = require('request'); var Q = require('q'); var xml2js = require('xml2js'); var moment = require('moment'); var injection = require('allcountjs'); injection.bindFactory('port', 9080); injection.bindFactory('dbUrl', 'mongodb://localhost:27017/toptal-community'); injection.bindFactory('gitRepoUrl', 'app-config'); injection.bindFactory('DiscussionEventsImport', function (Crud) { return { importEvents: function () { return Q.nfcall(request, "https://www.toptal.com/blog.rss").then(function (responseAndBody) { var body = responseAndBody[1]; return Q.nfcall(xml2js.parseString, body).then (function (feed) { var events = feed.rss.channel[0].item.map(function (item) { return { eventName: "Discussion of " + item.title, date: moment(item.pubDate, "DD MMM YYYY").add(1, 'day').toDate(), time: "12:00" }}); var crud = Crud.crudForEntityType('Event'); return Q.all(events.map(function (event) { return crud.find({query: {eventName: event.eventName}}).then(function (createdEvent) { if (!createdEvent[0]) { return crud.createEntity(event); } }); } )); }); }) } }; }); var server = injection.inject('allcountServerStartup'); server.startup(function (errors) { if (errors) { throw new Error(errors.join('\n')); } });

Bu dosyada, main.js dosyamızda kullanabileceğimiz “DiscussionEventsImport” adlı bir bağımlılık tanımlıyoruz ve “Event” varlık tipine bir içe aktarma eylemi ekleyerek.

 { id: "import-blog-events", name: "Import Blog Events", actionTarget: "all-items", perform: function (DiscussionEventsImport, Actions) { return DiscussionEventsImport.importEvents().then(function () { return Actions.refreshResult() }); } }

JavaScript dosyalarında bazı değişiklikler yaptıktan sonra sunucuyu yeniden başlatmak önemli olduğundan, önceki örneği öldürebilir ve öncekiyle aynı komutu uygulayarak yeniden başlatabilirsiniz:

 node toptal-community.js

Her şey yolunda giderse, "Blog Etkinliklerini İçe Aktar" eylemini çalıştırdıktan sonra aşağıdaki ekran görüntüsüne benzer bir şey göreceksiniz.

Blog Etkinliklerini İçe Aktar eylemi

Buraya kadar iyi ama burada durmayalım. Varsayılan görünümler işe yarar, ancak bazen sıkıcı olabilir. Onları biraz özelleştirelim.

Kartları sever misin? Herkes kartları sever! Bir kart görünümü oluşturmak için aşağıdakileri app-config dizininin içindeki event.jade adlı bir dosyaya koyun:

 extends main include mixins block vars - var hasToolbar = true block content .refresh-form-controller(ng-app='allcount', ng-controller='EntityViewController') +defaultToolbar() .container.screen-container(ng-cloak) +defaultList() .row: .col-lg-4.col-md-6.col-xs-12(ng-repeat="item in items") .panel.panel-default .panel-heading h3 {{item.date | date}} {{item.time}} div button.btn.btn-default.btn-xs(ng-if="!isInEditMode", lc-tooltip="View", ng-click="navigate(item.id)"): i.glyphicon.glyphicon-chevron-right |   button.btn.btn-danger.btn-xs(ng-if="isInEditMode", lc-tooltip="Delete", ng-click="deleteEntity(item)"): i.glyphicon.glyphicon-trash .panel-body h3 {{item.eventName}} +noEntries() +defaultEditAndCreateForms() block js +entityJs()

Bundan sonra, main.js'deki "Event" varlığından "customView: "events" olarak başvurmanız yeterlidir. Uygulamanızı çalıştırın ve varsayılan tablo arayüzü yerine kart tabanlı bir arayüz görmelisiniz.

main.js'deki olay varlığı

Çözüm

Günümüzde, web uygulamalarının geliştirme akışı, bazı işlemlerin tekrar tekrar tekrarlandığı birçok web teknolojisinde benzerdir. Gerçekten buna değer mi? Belki de web uygulamalarınızın geliştirilme şeklini yeniden düşünmenin zamanı gelmiştir?

AllcountJS, hızlı uygulama geliştirme çerçevelerine alternatif bir yaklaşım sunar; varlık tanımlarını tanımlayarak uygulama için bir iskelet oluşturarak başlarsınız ve ardından etrafına görünümler ve davranış özelleştirmeleri eklersiniz. Gördüğünüz gibi, AllcountJS ile yüz satırdan daha az kodla basit ama tamamen işlevsel bir uygulama oluşturduk. Belki tüm üretim gereksinimlerini karşılamıyor, ancak özelleştirilebilir. Tüm bunlar, AllcountJS'yi web uygulamalarının hızla önyüklenmesi için iyi bir araç haline getirir.