我的2017年终总结(PF项目框架设计心得分享 1.0rc new)
一晃眼又过去了一年,在这一年里尽管有许多不如意的事,却阻挡不了我前进的脚步。先用一句话来总结去年一年的状态,那就是“无休无止的忙碌”。而这样的忙碌状态对我来说是不可取的,因为匮乏的忙碌只能让头脑处于一种混乱而机械的状态中。在去年的时间就是工作上的烦心事困扰着我,虽有许多不错的主意终究因为忙碌而没有坚持,最后发现这的确是自己犯下的最大错误,因为后来不得不花更多时间来弥补。希望我的总结能够帮助到更多的朋友,从错误里汲取经验教训。
总结
所得:在工作中我能涉及到许多我以前认为十分复杂的领域,结果发现它们并没有想象中的困难。从这一点里我学习到一切看似困难的东西,只是我们自己胆怯造成的,在没有尝试之前就妄下结论是多么愚蠢啊。之前我在另一个城市里就是因为不相信自己,而丧失了许多的机会,如果有了这些机会我事业上恐怕不会如今天这般不顺。所以我希望所有在困难面前畏首畏尾的朋友,你们大胆一点放开你们的怀抱,去拥抱那即将靠近的梦想,虽然无法保证结果可能是一次惨痛的失败。可是你不趁着你还敢梦想的年纪,那么后面的生活你就只能活在遗憾当中了。
所失:忙碌让我的神经麻木,甚至身体也有点力不从心,这就造成我在自己理想面前放慢了脚步。在此我也希望各位朋友要重视自己的健康,就算工作再怎么幸苦也不能因为拼命而轻视了它,别将生活的压力想象的太大。毕竟只有一个完好的人,才能体会到美好的生活,而工作只不过是为了生活而服务的。
PF NEW
虽然自己的确因为时间和身体的原因,在这个框架上花费的时间少了许多,可是我却没有停止我对它的期许,那便是做到真正的简单易用。为了做到这个我从2015年开始到现在几乎花了三年时间修改了两次结构,而PF框架现在的版本已经到了2.1,其基本的功能和性能得到了一定的保证。其中过程的艰辛,恐怕没有几个人能体会到。
PF改动:plain server(2014)-> plain framework 1(2015-2016) -> plain framework 2(2017) -> plain framework new(2018)
我只有一个简单的年份和版本变化来表示PF框架的蜕变过程,其实是一场非常不容易的变化。一开始这个还不能称之框架,那个时候我只是想简单的应付工作上的事情,为服务器打造一个稳定的底层库,即2014年的plain server。接着我发现只争对服务器来说根本无法满足我的要求,于是我重新修改了结构让它能够支持几乎所有的常见应有。接着说道现在比较稳定的版本PF2,它的改动最大的就是从语法上直接用到了C++11,使得框架本身能够支持更多新特性。然而PF2还是不能满足我,我将要进行各大一步的调整,在PF2的基础上我修改了框架的目录结构,让它看起来更加清晰易懂。
PFnew的新特性:快速安装(框架、插件)、单元测试(框架、应用)、灵活封装(接口)
对于现在的PFnew的快速安装目前只支持UNIX/LINUX的平台,当然后续会想办法支持WINDOWS系统。而单元测试则使用了gtest,目的是让一些问题更能及早的发现,这一点我也会征求更多的意见,因为我之前虽然接触过这个框架,只是一直没有使用,而对这个测试框架来说也不知道它的优缺点。至于灵活封装就是移除了核心接口中的许多依赖,我将这部分东西移到了插件中,现在的插件中就有如脚本插件(lua)、数据库插件(odbc)、网络协议插件(google protobuf),而这些插件可以根据应用的需要又框架本身提供接口来加载使用。而且如果有人用心的话,可能会在框架里发现一个有趣的模块,那就是数据库的语法封装部分(DB QUERY BUILDER),会支持大部分的数据库语法,这样使得我们想要随意切换不同数据库提供了良好的支持,当然这部分仍旧是尝试阶段。而且关于这个语法封装器,我参考了Laravel(PHP框架)的代码,有兴趣的同仁可以去了解一下。
在这里贴一段代码来看看我们PFnew的数据库语法的支持以及单元测试示例:
#include "gtest/gtest.h"
#include "pf/engine/kernel.h"
#include "pf/db/query/grammars/grammar.h"
#include "pf/db/query/grammars/mysql_grammar.h"
#include "pf/db/connection.h"
#include "pf/db/query/builder.h"
#include "pf/support/helpers.h" enum {
kDBTypeODBC = ,
}; using namespace pf_db::query;
using namespace pf_basic::type; class DBQueryBuilder : public testing::Test { public:
static void SetUpTestCase() { GLOBALS["log.print"] = false; //First forbid the log print. GLOBALS["default.db.open"] = true;
GLOBALS["default.db.type"] = kDBTypeODBC;
GLOBALS["default.db.name"] = "pf_test";
GLOBALS["default.db.user"] = "root";
GLOBALS["default.db.password"] = "mysql"; engine_.add_libraryload("pf_plugin_odbc", {kDBTypeODBC}); engine_.init(); auto connection = new pf_db::Connection(engine_.get_db());
unique_move(pf_db::Connection, connection, connection_);
auto builder = new Builder(connection_.get(), nullptr);
unique_move(Builder, builder, builder_); auto mysql_grammar = new grammars::MysqlGrammar();
unique_move(grammars::Grammar, mysql_grammar, mysql_grammar_);
auto mysql_builder = new Builder(connection_.get(), mysql_grammar_.get());
unique_move(Builder, mysql_builder, mysql_builder_);
} static void TearDownTestCase() {
//std::cout << "TearDownTestCase" << std::endl;
} public:
virtual void SetUp() {
builder_->clear();
mysql_builder_->clear();
}
virtual void TearDown() {
} protected:
static pf_engine::Kernel engine_;
static std::unique_ptr<pf_db::Connection> connection_;
static std::unique_ptr<grammars::Grammar> mysql_grammar_;
static std::unique_ptr<Builder> builder_;
static std::unique_ptr<Builder> mysql_builder_; }; pf_engine::Kernel DBQueryBuilder::engine_;
std::unique_ptr<pf_db::Connection> DBQueryBuilder::connection_{nullptr};
std::unique_ptr<Builder> DBQueryBuilder::builder_{nullptr};
std::unique_ptr<Builder> DBQueryBuilder::mysql_builder_{nullptr};
std::unique_ptr<grammars::Grammar> DBQueryBuilder::mysql_grammar_{nullptr}; TEST_F(DBQueryBuilder, construct) {
Builder object(nullptr, nullptr);
pf_db::Connection connection(engine_.get_db());
Builder builder_test1(&connection, nullptr);
grammars::Grammar grammar;
Builder builder_test2(&connection, &grammar);
} TEST_F(DBQueryBuilder, testBasicSelect) {
builder_->select({"*"}).from("users");
ASSERT_STREQ("select * from \"users\"", builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testBasicSelectWithGetColumns) {
builder_->from("users").get();
ASSERT_TRUE(builder_->columns_.empty()); ASSERT_STREQ("select * from \"users\"", builder_->to_sql().c_str());
ASSERT_TRUE(builder_->columns_.empty());
} TEST_F(DBQueryBuilder, testBasicSelectUseWritePdo) { } TEST_F(DBQueryBuilder, testBasicTableWrappingProtectsQuotationMarks) {
builder_->select({"*"}).from("some\"table");
ASSERT_STREQ("select * from \"some\"\"table\"", builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testAliasWrappingAsWholeConstant) {
builder_->select({"x.y as foo.bar"}).from("baz");
ASSERT_STREQ("select \"x\".\"y\" as \"foo.bar\" from \"baz\"",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testAliasWrappingWithSpacesInDatabaseName) {
builder_->select({"w x.y.z as foo.bar"}).from("baz");
ASSERT_STREQ("select \"w x\".\"y\".\"z\" as \"foo.bar\" from \"baz\"",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testAddingSelects) {
builder_->select({"foo"}).
add_select({"bar"}).add_select({"baz", "boom"}).from("users");
ASSERT_STREQ("select \"foo\", \"bar\", \"baz\", \"boom\" from \"users\"",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testBasicSelectWithPrefix) {
builder_->get_grammar()->set_table_prefix("prefix_");
builder_->select({"*"}).from("users");
ASSERT_STREQ("select * from \"prefix_users\"",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testBasicSelectDistinct) {
builder_->distinct().select({"foo", "bar"}).from("users");
ASSERT_STREQ("select distinct \"foo\", \"bar\" from \"users\"",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testBasicAlias) {
builder_->select({"foo as bar"}).from("users");
ASSERT_STREQ("select \"foo\" as \"bar\" from \"users\"",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testAliasWithPrefix) {
builder_->get_grammar()->set_table_prefix("prefix_");
builder_->select({"*"}).from("users as people");
ASSERT_STREQ("select * from \"prefix_users\" as \"prefix_people\"",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testJoinAliasesWithPrefix) {
builder_->get_grammar()->set_table_prefix("prefix_");
builder_->select({"*"}).from("services").join(
"translations AS t", "t.item_id", "=", "services.id");
ASSERT_STREQ(
"select * from \"prefix_services\" inner join \"prefix_translations\" \
as \"prefix_t\" on \"prefix_t\".\"item_id\" = \"prefix_services\".\"id\"",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testBasicTableWrapping) {
builder_->select({"*"}).from("public.users");
ASSERT_STREQ("select * from \"public\".\"users\"",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testWhenCallback) {
auto callback = [](Builder *query, const variable_t &condition) {
ASSERT_TRUE(condition.get<bool>());
query->where("id", "=", );
};
builder_->select({"*"}).from("users").when(true, callback).where("email", "foo");
ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?",
builder_->to_sql().c_str()); builder_->clear();
builder_->select({"*"}).from("users").when(false, callback).where("email", "foo");
ASSERT_STREQ("select * from \"users\" where \"email\" = ?",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testWhenCallbackWithReturn) { } void assertEquals(
const variable_array_t &a, const variable_array_t &b, int32_t line = -) {
if (line != -)
std::cout << "assertEquals: " << line << std::endl;
ASSERT_TRUE(a.size() == b.size());
for (size_t i = ; i < a.size(); ++i)
ASSERT_STREQ(a[i].data.c_str(), b[i].data.c_str());
} TEST_F(DBQueryBuilder, testWhenCallbackWithDefault) {
auto callback = [](Builder *query, const variable_t &condition) {
ASSERT_STREQ(condition.c_str(), "truthy");
query->where("id", "=", );
};
auto def = [](Builder *query, const variable_t &condition) {
ASSERT_TRUE(condition == );
query->where("id", "=", );
}; builder_->select({"*"}).
from("users").when("truthy", callback, def).where("email", "foo");
ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?",
builder_->to_sql().c_str()); assertEquals({, "foo"}, builder_->get_bindings(), __LINE__); builder_->clear(); builder_->select({"*"}).
from("users").when(, callback, def).where("email", "foo");
ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?",
builder_->to_sql().c_str()); assertEquals({, "foo"}, builder_->get_bindings(), __LINE__);
} TEST_F(DBQueryBuilder, testUnlessCallback) {
auto callback = [](Builder *query, const variable_t &condition) {
ASSERT_FALSE(condition.get<bool>());
query->where("id", "=", );
}; builder_->select({"*"}).
from("users").unless(false, callback).where("email", "foo");
ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?",
builder_->to_sql().c_str()); builder_->clear();
builder_->select({"*"}).
from("users").unless(true, callback).where("email", "foo");
ASSERT_STREQ("select * from \"users\" where \"email\" = ?",
builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testUnlessCallbackWithReturn) { } TEST_F(DBQueryBuilder, testUnlessCallbackWithDefault) {
auto callback = [](Builder *query, const variable_t &condition) {
ASSERT_TRUE(condition == );
query->where("id", "=", );
};
auto def = [](Builder *query, const variable_t &condition) {
ASSERT_STREQ(condition.c_str(), "truthy");
query->where("id", "=", );
}; builder_->select({"*"}).
from("users").unless(, callback, def).where("email", "foo");
ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?",
builder_->to_sql().c_str()); assertEquals({, "foo"}, builder_->get_bindings(), __LINE__); builder_->clear(); builder_->select({"*"}).
from("users").unless("truthy", callback, def).where("email", "foo");
ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?",
builder_->to_sql().c_str()); assertEquals({, "foo"}, builder_->get_bindings(), __LINE__);
} TEST_F(DBQueryBuilder, testTapCallback) {
auto callback = [](Builder *query) {
query->where("id", "=", );
}; builder_->select({"*"}).from("users").tap(callback).where("email", "foo");
ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?",
builder_->to_sql().c_str());
} TEST_F(DBQueryBuilder, testBasicWheres) {
builder_->select({"*"}).from("users").where("id", "=", );
ASSERT_STREQ("select * from \"users\" where \"id\" = ?",
builder_->to_sql().c_str());
assertEquals({}, builder_->get_bindings());
} TEST_F(DBQueryBuilder, testMySqlWrappingProtectsQuotationMarks) {
/**
builder_->select({"*"}).from("some`table");
ASSERT_STREQ("select * from `some``table`",
builder_->to_sql().c_str());
**/
} TEST_F(DBQueryBuilder, testDateBasedWheresAcceptsTwoArguments) {
auto builder = mysql_builder_.get();
builder->select({"*"}).from("users").where_date("created_at", "");
ASSERT_STREQ("select * from `users` where date(`created_at`) = ?",
builder->to_sql().c_str()); builder->clear();
builder->select({"*"}).from("users").where_day("created_at", "");
ASSERT_STREQ("select * from `users` where day(`created_at`) = ?",
builder->to_sql().c_str()); builder->clear();
builder->select({"*"}).from("users").where_month("created_at", "");
ASSERT_STREQ("select * from `users` where month(`created_at`) = ?",
builder->to_sql().c_str()); builder->clear();
builder->select({"*"}).from("users").where_year("created_at", "");
ASSERT_STREQ("select * from `users` where year(`created_at`) = ?",
builder->to_sql().c_str());
} TEST_F(DBQueryBuilder, testWhereDayMySql) {
auto builder = mysql_builder_.get();
builder->select({"*"}).from("users").where_day("created_at", "=", );
ASSERT_STREQ("select * from `users` where day(`created_at`) = ?",
builder->to_sql().c_str());
assertEquals({}, builder->get_bindings());
} TEST_F(DBQueryBuilder, testWhereMonthMySql) {
auto builder = mysql_builder_.get();
builder->select({"*"}).from("users").where_month("created_at", "=", );
ASSERT_STREQ("select * from `users` where month(`created_at`) = ?",
builder->to_sql().c_str());
assertEquals({}, builder->get_bindings());
} TEST_F(DBQueryBuilder, testWhereYearMySql) {
auto builder = mysql_builder_.get();
builder->select({"*"}).from("users").where_year("created_at", "=", );
ASSERT_STREQ("select * from `users` where year(`created_at`) = ?",
builder->to_sql().c_str());
assertEquals({}, builder->get_bindings());
} TEST_F(DBQueryBuilder, testWhereTimeMySql) {
auto builder = mysql_builder_.get();
builder->select({"*"}).from("users").where_time("created_at", "=", "22:00");
ASSERT_STREQ("select * from `users` where time(`created_at`) = ?",
builder->to_sql().c_str());
assertEquals({"22:00"}, builder->get_bindings());
} TEST_F(DBQueryBuilder, testWhereDatePostgres) { } TEST_F(DBQueryBuilder, testWhereDayPostgres) { } TEST_F(DBQueryBuilder, testWhereMonthPostgres) { } TEST_F(DBQueryBuilder, testWhereYearPostgres) { } TEST_F(DBQueryBuilder, testWhereDaySqlite) { } TEST_F(DBQueryBuilder, testWhereMonthSqlite) { } TEST_F(DBQueryBuilder, testWhereYearSqlite) { } TEST_F(DBQueryBuilder, testWhereDaySqlServer) { } TEST_F(DBQueryBuilder, testWhereMonthSqlServer) { } TEST_F(DBQueryBuilder, testWhereYearSqlServer) { } TEST_F(DBQueryBuilder, testWhereBetweens) {
builder_->select({"*"}).from("users").where_between("id", {, });
ASSERT_STREQ("select * from \"users\" where \"id\" between ? and ?",
builder_->to_sql().c_str());
assertEquals({, }, builder_->get_bindings()); builder_->clear();
builder_->select({"*"}).from("users").where_notbetween("id", {, });
ASSERT_STREQ("select * from \"users\" where \"id\" not between ? and ?",
builder_->to_sql().c_str());
assertEquals({, }, builder_->get_bindings());
} TEST_F(DBQueryBuilder, testBasicOrWheres) {
builder_->select({"*"}).
from("users").where("id", "=", ).or_where("email", "=", "foo");
ASSERT_STREQ("select * from \"users\" where \"id\" = ? or \"email\" = ?",
builder_->to_sql().c_str());
assertEquals({, "foo"}, builder_->get_bindings());
} TEST_F(DBQueryBuilder, testRawWheres) {
builder_->select({"*"}).
from("users").where_raw("id = ? or email = ?", {, "foo"});
ASSERT_STREQ("select * from \"users\" where id = ? or email = ?",
builder_->to_sql().c_str());
assertEquals({, "foo"}, builder_->get_bindings());
} TEST_F(DBQueryBuilder, testRawOrWheres) {
builder_->select({"*"}).
from("users").where("id", "=", ).or_where_raw("email = ?", {"foo"});
ASSERT_STREQ("select * from \"users\" where \"id\" = ? or email = ?",
builder_->to_sql().c_str());
assertEquals({, "foo"}, builder_->get_bindings());
}
PFnew地址
https://github.com/viticm/plain
我的2017年终总结(PF项目框架设计心得分享 1.0rc new)的更多相关文章
- 我的2016年终总结(PF项目框架设计心得分享 2.0rc)
在无数的日夜里,熬出了多少的黑眼圈,致勤勤恳恳工作的各位朋友与自己.每到了年末的时候总想写的什么,主要是为了回顾以往一年里到底做了什么,这便是年终总结的主要意义.在此我将要总结的是和我在技术层面上成长 ...
- (三) Angular2项目框架搭建心得
前言: 在哪看到过angular程序员被React程序员鄙视,略显尴尬,确实Angular挺值得被调侃的,在1.*版本存在的几个性能问题,性能优化的"潜规则"贼多,以及从1.*到2 ...
- 【iOS】小项目框架设计(ReactiveCocoa+MVVM+AFNetworking+FMDB)
上一个项目使用到了ReactiveCocoa+MVVM+AFNetworking+FMDB框架设计,从最初的尝试,到后来不断思考和学习,现在对这样一个整体设计还是有了一定了理解与心得.在此与大家分享下 ...
- MegEngine 框架设计
MegEngine 框架设计 MegEngine 技术负责人许欣然将带了解一个深度学习框架是如何把网络的定义逐步优化并最终执行的,从框架开发者的视角来看待深度学习. 背景 AI 浪潮一波又一波,仿佛不 ...
- Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇——多页面VueSSR+热更新Server)
Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇--多页面VueSSR+热更新Server) @(HTML/JS) 这是Vue多页面框架系列文章的第二篇,上一篇(纯前 ...
- 发现2017年最好的CSS框架
如今,无数的框架出现在定期而少数人喜欢自助,Foundation和angular.js主宰了整个世界的发展.CSS代表用于描述HTML(或XML)文档表示的样式表语言.一个框架被定义为一个包,它由一组 ...
- Android 从零开始搭建一个主流项目框架—RxJava2.0+Retrofit2.0+OkHttp
我这里的网络请求是用的装饰者模式去写的,什么是装饰者模式呢?在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象.我的理解就是一个接口, ...
- Angular企业级开发(5)-项目框架搭建
1.AngularJS Seed项目目录结构 AngularJS官方网站提供了一个angular-phonecat项目,另外一个就是Angular-Seed项目.所以大多数团队会基于Angular-S ...
- 2_MVC+EF+Autofac(dbfirst)轻型项目框架_用户权限验证
前言 接上面两篇 0_MVC+EF+Autofac(dbfirst)轻型项目框架_基本框架 与 1_MVC+EF+Autofac(dbfirst)轻型项目框架_core层(以登陆为例) .在第一篇中介 ...
随机推荐
- 认识Java(2)
注释 对程序的一段文字描述 可方便其他用户的阅读,增加代码的可读性.可以注销掉代码,等需要的时候再用. 编译器会自动忽视被注释的内容. 分类: 单行注释 // 多行注释 /* */ 文档注释/** * ...
- Maven打包时去掉项目版本号
Maven打包后,jar或war文件名里带有版本号信息,如projectname0.0.1-SNAPSHOT.jar等,怎么去掉呢? 解决办法: 打开项目pom.xml文件,在<build> ...
- ap web
apapplication端吧 应用程序端 也C-S架构Cweb网页端 般封装httpservletrequest和httpservletresponse对象处理些操作 b-s架构
- Codeforces 437 D. The Child and Zoo 并查集
题目链接:D. The Child and Zoo 题意: 题意比较难懂,是指给出n个点并给出这些点的权值,再给出m条边.每条边的权值为该条路连接的两个区中权值较小的一个.如果两个区没有直接连接,那么 ...
- 如何安装 Composer
下载 Composer 安装前请务必确保已经正确安装了 PHP.打开命令行窗口并执行 php -v 查看是否正确输出版本号. 打开命令行并依次执行下列命令安装最新版本的 Composer: php - ...
- ECLIPS-S测井系统下的仪器挂接 [TCC模块]
1. 环境 HPUX版本:11.23 Complete Image ECLIPS版本:Rel 5.1i 2. 效果图 3. 用途 为以后在此系统中挂接新仪器打下坚实的基础. 4. 参考资料 ECLIP ...
- 一步步使用BMC Atrium Orchestrator Vmware Infrastructure Event Monitor
本教程将一步步演示怎么使用BMC Atrium Orchestrator (BAO) Vmware Infrastructure Event Monitor来监控VSphere Webservice的 ...
- 反射应用--IOC和AOP
反射最大的价值就是用来写框架,下面贴出自己的3篇代码,模拟实现SPING框架的bean工厂,IOC,AOP.当然这里重点是在利用反射实现功能,为了图方便,我用的是Properties文件,关于XML后 ...
- TCP/IP详解 卷1 第二十章 TCP的成块数据流
先补充一个知识: 1.停止等待协议:是tcp保证传输可靠的重要途径,"停止等待"就是指发送完一个分组就停止发送,等待对方确认之后,才能继续发送下一个分组 停止等待协议的优点是简单, ...
- 04_Javascript初步第二天(下)
错误对象 try{ aa();//这是一个未被定义的方法 }catch(e){ alert(e.name+":"+e.message);//输出:ReferenceError:aa ...