一晃眼又过去了一年,在这一年里尽管有许多不如意的事,却阻挡不了我前进的脚步。先用一句话来总结去年一年的状态,那就是“无休无止的忙碌”。而这样的忙碌状态对我来说是不可取的,因为匮乏的忙碌只能让头脑处于一种混乱而机械的状态中。在去年的时间就是工作上的烦心事困扰着我,虽有许多不错的主意终究因为忙碌而没有坚持,最后发现这的确是自己犯下的最大错误,因为后来不得不花更多时间来弥补。希望我的总结能够帮助到更多的朋友,从错误里汲取经验教训。

总结

  所得:在工作中我能涉及到许多我以前认为十分复杂的领域,结果发现它们并没有想象中的困难。从这一点里我学习到一切看似困难的东西,只是我们自己胆怯造成的,在没有尝试之前就妄下结论是多么愚蠢啊。之前我在另一个城市里就是因为不相信自己,而丧失了许多的机会,如果有了这些机会我事业上恐怕不会如今天这般不顺。所以我希望所有在困难面前畏首畏尾的朋友,你们大胆一点放开你们的怀抱,去拥抱那即将靠近的梦想,虽然无法保证结果可能是一次惨痛的失败。可是你不趁着你还敢梦想的年纪,那么后面的生活你就只能活在遗憾当中了。

  所失:忙碌让我的神经麻木,甚至身体也有点力不从心,这就造成我在自己理想面前放慢了脚步。在此我也希望各位朋友要重视自己的健康,就算工作再怎么幸苦也不能因为拼命而轻视了它,别将生活的压力想象的太大。毕竟只有一个完好的人,才能体会到美好的生活,而工作只不过是为了生活而服务的。

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)的更多相关文章

  1. 我的2016年终总结(PF项目框架设计心得分享 2.0rc)

    在无数的日夜里,熬出了多少的黑眼圈,致勤勤恳恳工作的各位朋友与自己.每到了年末的时候总想写的什么,主要是为了回顾以往一年里到底做了什么,这便是年终总结的主要意义.在此我将要总结的是和我在技术层面上成长 ...

  2. (三) Angular2项目框架搭建心得

    前言: 在哪看到过angular程序员被React程序员鄙视,略显尴尬,确实Angular挺值得被调侃的,在1.*版本存在的几个性能问题,性能优化的"潜规则"贼多,以及从1.*到2 ...

  3. 【iOS】小项目框架设计(ReactiveCocoa+MVVM+AFNetworking+FMDB)

    上一个项目使用到了ReactiveCocoa+MVVM+AFNetworking+FMDB框架设计,从最初的尝试,到后来不断思考和学习,现在对这样一个整体设计还是有了一定了理解与心得.在此与大家分享下 ...

  4. MegEngine 框架设计

    MegEngine 框架设计 MegEngine 技术负责人许欣然将带了解一个深度学习框架是如何把网络的定义逐步优化并最终执行的,从框架开发者的视角来看待深度学习. 背景 AI 浪潮一波又一波,仿佛不 ...

  5. Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇——多页面VueSSR+热更新Server)

    Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇--多页面VueSSR+热更新Server) @(HTML/JS) 这是Vue多页面框架系列文章的第二篇,上一篇(纯前 ...

  6. 发现2017年最好的CSS框架

    如今,无数的框架出现在定期而少数人喜欢自助,Foundation和angular.js主宰了整个世界的发展.CSS代表用于描述HTML(或XML)文档表示的样式表语言.一个框架被定义为一个包,它由一组 ...

  7. Android 从零开始搭建一个主流项目框架—RxJava2.0+Retrofit2.0+OkHttp

    我这里的网络请求是用的装饰者模式去写的,什么是装饰者模式呢?在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象.我的理解就是一个接口, ...

  8. Angular企业级开发(5)-项目框架搭建

    1.AngularJS Seed项目目录结构 AngularJS官方网站提供了一个angular-phonecat项目,另外一个就是Angular-Seed项目.所以大多数团队会基于Angular-S ...

  9. 2_MVC+EF+Autofac(dbfirst)轻型项目框架_用户权限验证

    前言 接上面两篇 0_MVC+EF+Autofac(dbfirst)轻型项目框架_基本框架 与 1_MVC+EF+Autofac(dbfirst)轻型项目框架_core层(以登陆为例) .在第一篇中介 ...

随机推荐

  1. RMQ算法 (ST算法)

     概述: RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中 ...

  2. struts学习总结

    -- struts2 是在struts1和webwork基础上发展的全新框架. -- struts2解决的问题: 原始的servlet中,每需要操作一个crud的操作就要创建一个servlet,虽然后 ...

  3. javascript学习日志:前言

    javascript学习日志系列的所有博客,主要理论依据是<javascript权威指南>(犀牛书第6版)以及<javascript高级程序设计第三版>(红色书),目前js行业 ...

  4. js实现最短时间走完不同速度的路程

    题目: 现在有一条公路,起点是0公里,终点是100公里.这条公路被划分为N段,每一段有不同的限速.现在他们从A公里处开始,到B公里处结束.请帮他们计算在不超过限速的情况下,最少需要多少时间完成这段路程 ...

  5. getResource()和getSystemResource()分析

    1. getClass().getResource() 第一步,getClass().getResource(path)是有一个路径参数的,这个路径会先被转换成"类所在的包名称+path&q ...

  6. 【转】MATLAB图形句柄(二)

        MATLAB图形句柄   1.1 图形对象及其句柄 1.2 图形对象属性 1.3 图形对象的创建 1.1 图形对象及其句柄 1.图形对象 MATLAB的图形对象包括计算机屏幕.图形窗口.坐标轴 ...

  7. python3中,os.path模块下常用的用法总结

    abspath basename dirname exists getatime getctime getmtime getsize isabs isdir isfile islink ismount ...

  8. wpf datagrid row height 行高自动计算使每行行高自适应文本

    wpf 的datagrid的行高 要么是Auto,要么是定值:但会带来麻烦就是每行行高都一样. 当需要按内容(主要是wrap 换行的textbox或textblock)来动态调整行高的时候,需要用到d ...

  9. MySQL用户授权与权限

    MySQL权限如下表 权限名字 权限说明 Context CREATE 允许创建新的数据库和表 Databases, tables, or indexes DROP 允许删除现有数据库.表和视图 Da ...

  10. SpringMVC源码情操陶冶-InterceptorsBeanDefinitionParser拦截器解析器

    解析mvc:interceptors节点 观察下InterceptorsBeanDefinitionParser的源码备注 /** * {@link org.springframework.beans ...