cici 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-build-manifest.json +13 -13
  3. package/.next/standalone/.next/app-path-routes-manifest.json +1 -1
  4. package/.next/standalone/.next/build-manifest.json +2 -2
  5. package/.next/standalone/.next/prerender-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  7. package/.next/standalone/.next/server/app/api/asset/[...path]/route.js +1 -1
  8. package/.next/standalone/.next/server/app/api/asset/[...path]/route.js.nft.json +1 -1
  9. package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/comments/[cid]/reactions/route.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/comments/[cid]/route.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/replies/route.js.nft.json +1 -1
  12. package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/resolve/route.js.nft.json +1 -1
  13. package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/route.js.nft.json +1 -1
  14. package/.next/standalone/.next/server/app/api/blog/[id]/highlights/route.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/api/graphql/route.js.nft.json +1 -1
  16. package/.next/standalone/.next/server/app/api/mile/prompts.body +1 -1
  17. package/.next/standalone/.next/server/app/api/upload/route.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/atom.xml/route.js +3 -3
  19. package/.next/standalone/.next/server/app/atom.xml/route.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/atom.xml.body +1 -1677
  21. package/.next/standalone/.next/server/app/blog/[id]/page.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/blog/[id]/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/blog/page.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/blog/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/.next/server/app/editor/page.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/editor/page_client-reference-manifest.js +1 -1
  27. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  28. package/.next/standalone/.next/server/app/memos/page.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/memos/page_client-reference-manifest.js +1 -1
  30. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/robots.txt/route.js +1 -1
  33. package/.next/standalone/.next/server/app/rss.xml/route.js +2 -2
  34. package/.next/standalone/.next/server/app/rss.xml/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/rss.xml.body +1 -227
  36. package/.next/standalone/.next/server/app/sitemap.xml/route.js +5 -5
  37. package/.next/standalone/.next/server/app/sitemap.xml.body +5 -101
  38. package/.next/standalone/.next/server/app/unavailable/page_client-reference-manifest.js +1 -1
  39. package/.next/standalone/.next/server/app-paths-manifest.json +6 -6
  40. package/.next/standalone/.next/server/chunks/3464.js +1 -1
  41. package/.next/standalone/.next/server/chunks/3607.js +1 -1
  42. package/.next/standalone/.next/server/chunks/719.js +1 -1
  43. package/.next/standalone/.next/server/pages/500.html +1 -1
  44. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  45. package/.next/standalone/package.json +2 -2
  46. package/.next/standalone/sample-content/blog/hello-cici.md +25 -0
  47. package/.next/standalone/sample-content/likes.json +1 -0
  48. package/.next/standalone/sample-content/memos.json +7 -0
  49. package/.next/standalone/sample-content/site-config.json +18 -0
  50. package/README.md +17 -1
  51. package/bin/cici.js +126 -23
  52. package/package.json +2 -2
  53. package/.next/standalone/data/assets/1727016079577.jpg +0 -0
  54. package/.next/standalone/data/assets/images/2024-12-03/1733256504772.jpg +0 -0
  55. package/.next/standalone/data/assets/images/2024-12-12/.gitkeep +0 -0
  56. package/.next/standalone/data/assets/images/2024-12-12/1734033798997.png +0 -0
  57. package/.next/standalone/data/assets/images/2024-12-21/.gitkeep +0 -0
  58. package/.next/standalone/data/assets/images/2024-12-21/1734785902890.jpeg +0 -0
  59. package/.next/standalone/data/assets/images/2024-12-23/.gitkeep +0 -0
  60. package/.next/standalone/data/assets/images/2024-12-23/1734990512413.jpeg +0 -0
  61. package/.next/standalone/data/assets/images/2024-12-23/1734991833894.jpeg +0 -0
  62. package/.next/standalone/data/assets/images/2024-12-23/1734993188114.jpeg +0 -0
  63. package/.next/standalone/data/assets/images/2024-12-23/1734993280313.jpeg +0 -0
  64. package/.next/standalone/data/assets/images/2024-12-23/1734993317984.jpeg +0 -0
  65. package/.next/standalone/data/assets/images/2024-12-23/1734993411252.jpeg +0 -0
  66. package/.next/standalone/data/assets/images/2024-12-23/1734993425042.jpeg +0 -0
  67. package/.next/standalone/data/assets/images/2024-12-23/1734993480342.jpeg +0 -0
  68. package/.next/standalone/data/assets/images/2024-12-23/1734993562660.jpeg +0 -0
  69. package/.next/standalone/data/assets/images/2024-12-23/1734993625024.jpeg +0 -0
  70. package/.next/standalone/data/assets/images/2024-12-23/1734993677103.jpeg +0 -0
  71. package/.next/standalone/data/assets/images/2024-12-23/1734993893285.jpeg +0 -0
  72. package/.next/standalone/data/assets/images/2024-12-23/1734993996131.jpeg +0 -0
  73. package/.next/standalone/data/assets/images/2024-12-23/1734994035144.jpeg +0 -0
  74. package/.next/standalone/data/assets/images/2024-12-23/1734994064317.jpeg +0 -0
  75. package/.next/standalone/data/assets/images/2024-12-23/1734994128679.jpeg +0 -0
  76. package/.next/standalone/data/assets/images/2024-12-23/1734994189257.jpeg +0 -0
  77. package/.next/standalone/data/assets/images/2024-12-23/1734994521799.jpeg +0 -0
  78. package/.next/standalone/data/assets/images/2024-12-23/1734994530669.jpeg +0 -0
  79. package/.next/standalone/data/assets/images/2024-12-24/.gitkeep +0 -0
  80. package/.next/standalone/data/assets/images/2024-12-24/1735032434591.jpeg +0 -0
  81. package/.next/standalone/data/assets/images/2024-12-24/1735068363518.jpeg +0 -0
  82. package/.next/standalone/data/assets/images/Cofe-app.png +0 -0
  83. package/.next/standalone/data/blog/.gitkeep +0 -0
  84. package/.next/standalone/data/blog/2017-summary.md +0 -59
  85. package/.next/standalone/data/blog/a-complex-web-app-refactor.md +0 -72
  86. package/.next/standalone/data/blog/a-day-of-remote-worker.md +0 -82
  87. package/.next/standalone/data/blog/async-action-in-redux.md +0 -257
  88. package/.next/standalone/data/blog/cofe.md +0 -398
  89. package/.next/standalone/data/blog/expensee-shortcut-numbers-guide.md +0 -99
  90. package/.next/standalone/data/blog/first-golang-project-fx.md +0 -113
  91. package/.next/standalone/data/blog/work-going-index.md +0 -49
  92. package/.next/standalone/data/blog//344/270/212/346/265/267/345/210/260/351/230/277/345/247/206/346/226/257/347/211/271/344/270/271.md +0 -114
  93. package/.next/standalone/data/blog//344/272/214/346/234/210/350/221/241/350/220/204/347/211/231/346/270/270/350/256/260.md +0 -107
  94. package/.next/standalone/data/blog//345/215/216/344/270/272/351/270/277/350/222/231-harmaryos-next-/347/272/277/344/270/213/346/264/273/345/212/250/345/260/217/350/256/260.md +0 -180
  95. package/.next/standalone/data/blog//345/233/233/346/234/210/347/232/204/345/260/276/345/267/264/351/200/233/345/276/267/345/233/275-/346/237/217/346/236/227.md +0 -76
  96. package/.next/standalone/data/blog//345/234/250/344/274/246/346/225/246-shoreditch-/345/221/206/344/270/211/345/244/251.md +0 -40
  97. package/.next/standalone/data/blog//346/204/217/345/244/247/345/210/251/347/275/227/351/251/254/345/244/217/345/244/251/345/233/233/346/227/245/346/270/270.md +0 -59
  98. package/.next/standalone/data/blog//346/210/221/345/201/232/344/272/206/344/270/200/346/254/276/346/227/205/350/241/214/350/256/260/345/275/225/345/272/224/347/224/250/357/274/232mile.md +0 -40
  99. package/.next/standalone/data/blog//350/245/277/347/217/255/347/211/231/344/270/203/345/244/251/347/232/204/346/227/205/350/241/214.md +0 -128
  100. package/.next/standalone/data/blog//351/200/233/351/200/233/346/265/216/345/267/236/345/262/233.md +0 -78
  101. package/.next/standalone/data/blog-manifest.json +0 -21
  102. package/.next/standalone/data/highlights/expensee-shortcut-numbers-guide.json +0 -77
  103. package/.next/standalone/data/likes.json +0 -56
  104. package/.next/standalone/data/memos.json +0 -1255
  105. package/.next/standalone/data/site-config.json +0 -22
  106. /package/.next/standalone/.next/static/{ACh2hmfOOZR7INKDQAX5I → Pl18p4h2shbbqjypPxStc}/_buildManifest.js +0 -0
  107. /package/.next/standalone/.next/static/{ACh2hmfOOZR7INKDQAX5I → Pl18p4h2shbbqjypPxStc}/_ssgManifest.js +0 -0
  108. /package/.next/standalone/{data → sample-content/assets}/.gitkeep +0 -0
  109. /package/.next/standalone/{data/assets/images/2024-12-03 → sample-content/highlights}/.gitkeep +0 -0
@@ -4,7 +4,7 @@
4
4
  <subtitle>Minghe's personal blog sharing travel experiences across Europe and Asia, tech insights, and daily thoughts.</subtitle>
5
5
  <link href="https://blog.minghe.me/atom.xml" rel="self"/>
6
6
  <link href="https://blog.minghe.me"/>
7
- <updated>2026-05-28T10:00:00.000Z</updated>
7
+ <updated>2026-07-20T22:01:21.131Z</updated>
8
8
  <id>https://blog.minghe.me/</id>
9
9
  <author>
10
10
  <name>Minghe</name>
@@ -12,1680 +12,4 @@
12
12
  </author>
13
13
  <generator>Next.js</generator>
14
14
 
15
- <entry>
16
- <title>用 iOS 快捷指令 + Numbers 做一套零依赖的记账系统</title>
17
- <link href="https://blog.minghe.me/blog/expensee-shortcut-numbers-guide"/>
18
- <updated>2026-05-28T10:00:00.000Z</updated>
19
- <id>https://blog.minghe.me/blog/expensee-shortcut-numbers-guide</id>
20
- <content type="html"><![CDATA[---
21
- title: 用 iOS 快捷指令 + Numbers 做一套零依赖的记账系统
22
- date: 2026-05-28T10:00:00.000Z
23
- latitude: 52.330390529537716
24
- longitude: 4.940213073274852
25
- city: Duivendrecht
26
- street: Kastanjepad
27
- ---
28
-
29
- [ExpenSee](https://milemile.app/expensee) 上线之前,我用了很久一套土法记账:iOS 自带的**快捷指令** + **Numbers**。一行代码不写,没有服务器,没有 API,也没有第三方账号。每次付完款,按一下手机背面,整个流程跑完,一笔账就写进了 iCloud 上一份普通的 Numbers 表格里。
30
-
31
- 这条快捷指令是 ExpenSee 这款 App 最初的灵感来源。这篇文章把这套流程从头讲一遍,给那些愿意自己折腾 iOS 自动化的人作个参考。
32
-
33
- > **iCloud 安装链接**:[https://www.icloud.com/shortcuts/c78c745e753541beb6a92e4f311b5c6f](https://www.icloud.com/shortcuts/c78c745e753541beb6a92e4f311b5c6f)
34
- >
35
- > **模版下载(备用)**:[https://milemile.app/expensee/static/template.numbers](https://milemile.app/expensee/static/template.numbers)
36
-
37
- ---
38
-
39
- ## 它到底做了什么
40
-
41
- 每次运行,这条快捷指令做的事情是:
42
-
43
- 1. 算出当前年份,组合出一个文件名 `2026账本.numbers`,去 iCloud 的 *Numbers* 文件夹找它。
44
- 2. 如果文件不存在,就从 [milemile.app/expensee/static/template.numbers](https://milemile.app/expensee/static/template.numbers) 下载一份模版,按当年的年份命名后保存进 iCloud Drive 的 Numbers 文件夹,然后退出。
45
- 3. 如果文件存在,就**截一张屏**(一般是支付宝 / 微信支付的支付完成页),用系统自带的图像识别把所有形如 `[0-9]+\.[0-9]{1,3}` 的数字找出来。
46
- 4. 只识别到一个金额时直接采用;多个金额会跳出列表让你挑选;都没识别到就改为手动输入。
47
- 5. 依次询问:**支出 / 收入** → **分类** → **账户**(支付宝 / 微信 / 银行卡)→ **备注**。
48
- 6. 调用 Numbers 的 *在电子表格中添加值* 系统动作,把这一行写进当月对应的 `M月支出账单` 或 `M月收入明细` 表格里。
49
-
50
- 分类是预设好的:
51
-
52
- - **支出**:数码电器、餐饮美食、自我提升、服饰装扮、日用百货、车辆交通、娱乐休闲、医疗健康、家庭支出、充值缴费、其他
53
- - **收入**:主业收入、副业收入、投资理财、红包礼金、其他
54
-
55
- 整个流程没有任何一步要联网到我或者别人的服务器,所有数据都留在你的 iCloud 里。
56
-
57
- ## 一次性设置
58
-
59
- 1. **加入快捷指令**。在 iPhone 上打开 [这条 iCloud 链接](https://www.icloud.com/shortcuts/c78c745e753541beb6a92e4f311b5c6f),点 *添加快捷指令*。这条快捷指令叫 *ExpenSee 自动记账*。
60
- 2. **确认 iCloud 同步开着**:*设置 → 你的姓名 → iCloud → iCloud 云盘*,并确保 Numbers 在同步列表里。
61
- 3. **跑一次快捷指令**。如果你还没有当年的账本文件,它会下载模版并保存为 `{年份}账本.numbers`。看到 *设置成功,重新运行开始记账吧* 的提示就成功了。
62
- 4. **如果第一次卡住不动**(极少数情况下模版下载会很慢),手动从 [milemile.app/expensee/static/template.numbers](https://milemile.app/expensee/static/template.numbers) 下载文件,重命名为 `2026账本.numbers`(把年份换成当前),放到 iCloud 的 Numbers 文件夹里,再运行快捷指令即可。
63
-
64
- ## 怎么用:每天三秒
65
-
66
- 记账这件事最大的成本是从付款到入账之间的几秒钟。这条快捷指令的目标就是把这几秒压到极致:
67
-
68
- 1. 付款后停留在金额完成页;
69
- 2. 按下你绑定的快捷键(见下一节);
70
- 3. 系统自动截屏并识别金额,确认或挑选;
71
- 4. 选支出 / 收入、分类、账户,写一句备注,结束。
72
-
73
- 整个过程从掏出手机到结束大概 5 秒。
74
-
75
- ## 三种触发方式
76
-
77
- 把快捷指令绑到一个"一按就开始"的动作,是这套流程能跑下去的关键。下面三种任选其一:
78
-
79
- ### ① 操作按钮(iPhone 15 Pro 起)
80
-
81
- > *设置 → 操作按钮 → 选择"快捷指令" → 选择"ExpenSee 自动记账"*
82
-
83
- 绑定之后,长按机身侧面的橙色按钮就启动整套流程。我自己是 15 Pro 用户,这是我用得最顺手的方式——付完款顺手长按一下,相当于把记账的"启动成本"降到了零。
84
-
85
- ### ② 轻点背面(所有支持的 iPhone)
86
-
87
- > *设置 → 辅助功能 → 触控 → 轻点背面 → 轻点两下(或三下)→ 快捷指令 → ExpenSee 自动记账*
88
-
89
- 用手指轻敲两下手机背面就触发——不需要解锁回到主屏,不需要长按某个固定按钮,连戴着手机壳也照样能识别。这是没有操作按钮的 iPhone(XS、11、12、13、14 系列、所有非 Pro 机型)的最优解。
90
-
91
- ### ③ Siri 语音
92
-
93
- 直接对 Siri 说"ExpenSee 自动记账"。开车、做饭、手不空的时候最好用,但因为后续还需要点击挑选金额、分类等等,并不像前两个那样真的"全程不抬头",所以平时主要是兜底用。
94
-
95
- ## 数据在哪里
96
-
97
- 所有交易都写在 iCloud 上的 Numbers 文件 `{年份}账本.numbers` 里。每一年一份新表,按月分了 12 张工作表(`1月数据库` 到 `12月数据库`),每张工作表里有 *支出* / *收入* 两个表格。
98
-
99
- 因为这是一份普通的 Numbers 文档,你可以在任何 Apple 设备上:
100
-
101
- - 直接做求和、按分类透视、画图表;
102
- - 导出 CSV / Excel 给会计或税务;
103
- - 用 iCloud Drive 备份,或者手动下载一份留底。
104
-
105
- 没有任何数据离开你的 iCloud。如果哪一天我这套生态都消失了,你的账本依然是一份完整、可读的 Numbers 文件。
106
-
107
- ## 局限性,以及为什么我后来做了 ExpenSee
108
-
109
- 用了一年多之后,几个不舒服的地方逐渐放大:
110
-
111
- - **截屏 OCR 的识别率不稳定**。支付宝的金额数字字体大、对比强,识别没问题;但小红书、B 站、点外卖小票里的金额有时识别不到,就要手动输入。
112
- - **每年初要手动初始化**——快捷指令是按 `{年份}账本.numbers` 命名的,跨年那天的第一笔会触发模版下载流程,不是无缝的。
113
- - **多币种很难做**。Numbers 公式可以处理,但快捷指令本身没办法在记账的时候就帮你转换。
114
- - **分类是写死的**——加一个新分类要改快捷指令,不是普通用户能接受的成本。
115
-
116
- [ExpenSee](https://apps.apple.com/us/app/expensee-expense-tracking-ai/id6448993636) 把这件事的核心——把记账压到几秒——做成一个独立的 iOS 应用。同样不依赖任何外部服务,但识别准、原生支持多币种、日历视图能让你一眼看清这一个月。如果你想要这条快捷指令的"升级版",可以去 App Store 试试。
117
-
118
- 但如果你像我一样喜欢自己拼装工具,这条快捷指令依然是个不错的起点。它的全部源码就在你的 iPhone 上,可以随便改成你喜欢的样子——加分类、改账户、换币种、接到不同的 Numbers 表格里,都只是几下点击。
119
- ]]></content>
120
- <published>2026-05-28T10:00:00.000Z</published>
121
- </entry>
122
- <entry>
123
- <title>我做了一款旅行记录应用:Mile</title>
124
- <link href="https://blog.minghe.me/blog/%E6%88%91%E5%81%9A%E4%BA%86%E4%B8%80%E6%AC%BE%E6%97%85%E8%A1%8C%E8%AE%B0%E5%BD%95%E5%BA%94%E7%94%A8%EF%BC%9Amile"/>
125
- <updated>2026-01-21T21:30:38.089Z</updated>
126
- <id>https://blog.minghe.me/blog/%E6%88%91%E5%81%9A%E4%BA%86%E4%B8%80%E6%AC%BE%E6%97%85%E8%A1%8C%E8%AE%B0%E5%BD%95%E5%BA%94%E7%94%A8%EF%BC%9Amile</id>
127
- <content type="html"><![CDATA[---
128
- title: 我做了一款旅行记录应用:Mile
129
- date: 2026-01-21T21:30:38.089Z
130
- latitude: 52.330390529537716
131
- longitude: 4.940213073274852
132
- city: Duivendrecht
133
- street: Kastanjepad
134
- ---
135
-
136
-
137
-
138
-
139
-
140
- 我很喜欢旅行,虽然去过的城市不多,但是每一次旅行都有着非常独特的记忆,我偶尔就会想想去看看我都去了哪儿,玩了什么, 遇到什么人,吃了什么好吃的, 碰到了什么奇怪的事情。
141
-
142
- 所以我就开发 [Mile](https://milemile.app) 这款iOS旅行记录应用,她是我和家人在巴塞罗那旅行的时候,在路边等公交车,突然间想做的一个工具,在巴塞罗那的后面几天晚上,在家人熟睡了之后,我就开始开发 [Mile](https://milemile.app) 。
143
-
144
- 现在她还处在很初期,远没有达到我心里想要的样子,但是她开始慢慢的完备了一些我想要的功能。
145
-
146
- ## 屏幕小组件
147
-
148
- 它漂亮直观展示我的旅行数据,每次看到都让我回想起那些难忘的旅程。
149
- ![Widget Light](https://github.com/metrue/Cofe/blob/main/assets/images/2026-01-21/1769030280576.jpeg?raw=true)
150
-
151
- ## 可分享的"数字护照"
152
-
153
- 这是我非常喜欢的功能,App能自动生成可视化的旅行总结,就像一本"数字护照"。它不仅美观,还方便我分享我的旅行故事。
154
- ![Sharable-Mile-Card.JPG](https://github.com/metrue/Cofe/blob/main/assets/images/2026-01-21/1769030364309.JPG?raw=true)
155
-
156
- ## 方便轻松的旅行记录
157
-
158
- 如何轻松输入旅行记录,这是我到现在仍然在思考,而且不断探索的。为了快速的导入数据,[Mile](https://milemile.app) 支持了系统日历同步, 也支持直接从相册中同步旅行信息;为了随时随地记录,[Mile](https://milemile.app) 支持了自然语言输入;为了拍照旅行过程的票据完成旅行记录,[Mile](https://milemile.app) 增加了拍照记录旅行的功能。但是直到现在,仍然有很多的改善空间。
159
-
160
- ![Mile-MainScreen.jpg](https://github.com/metrue/Cofe/blob/main/assets/images/2026-02-01/1769979064115.jpg?raw=true)
161
- ---
162
-
163
- "旅行似乎一本护照,和一张张的票据",这是当时在巴塞罗那街头,突然闪现到我脑海里的一句话。它是我做这款应用的原始和朴素的想法,欢迎大家尝试 [Mile](https://milemile.app) ,希望它能帮你留住某些珍贵的回忆。
164
- [Mile](https://milemile.app) 是一款付费应用:3 元。但是我准备了 100 个 Promo Codes,欢迎感兴趣的朋友[私信](mailto:h.minghe@gmail.com)我获取。
165
-
166
- 到 [App Store](https://apps.apple.com/us/app/mile-track-your-trips/id6757205061) 直接下载使用 [Mile](https://milemile.app) 吧,期待你的反馈!]]></content>
167
- <published>2026-01-21T21:30:38.089Z</published>
168
- </entry>
169
- <entry>
170
- <title>在伦敦 Shoreditch 呆三天</title>
171
- <link href="https://blog.minghe.me/blog/%E5%9C%A8%E4%BC%A6%E6%95%A6-shoreditch-%E5%91%86%E4%B8%89%E5%A4%A9"/>
172
- <updated>2025-10-06T09:28:06.524Z</updated>
173
- <id>https://blog.minghe.me/blog/%E5%9C%A8%E4%BC%A6%E6%95%A6-shoreditch-%E5%91%86%E4%B8%89%E5%A4%A9</id>
174
- <content type="html"><![CDATA[---
175
- title: 在伦敦 Shoreditch 呆三天
176
- date: 2025-10-06T09:28:06.524Z
177
- latitude: 37.793858561729316
178
- longitude: -122.39492676950107
179
- city: San Francisco
180
- street: Market Street
181
- external_discussions:
182
- - platform: v2ex
183
- url: https://v2ex.com/t/1163528
184
- ---
185
-
186
-
187
-
188
-
189
- > 最近一年多冲冲撞撞的来去一些地方,突然某些时刻觉得,原来自己也拥有了某种程度的自由,移动意义上的自由.
190
-
191
-
192
- ![IMG_7684.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-10-06/1759741751006.jpeg?raw=true)
193
-
194
- 三十几年的人生里,我大部分的时间都觉得自己钉在具体的地方,小时候没有想过我会离开家乡去外地读书,去北京,去上海,工作生活,去年以前没有想过自己会来欧洲工作生活; 最近一年更是越发的想体验世界,抓住小朋友的短假长假,带他们离开熟悉城市和国家,去陌生的地方走一走;甚至当把公开演讲能力训练提高的技术大会分享,也按照国家和城市认真的考虑投稿. 今年伦敦的APIDays和旧金山的GraphQL Summit都很幸运的入选了.
195
-
196
- ![IMG_7663.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-10-06/1759742871999.jpeg?raw=true)
197
-
198
- 第一次来伦敦,也是第一次来英国. 从阿姆斯特丹到伦敦很快,就四十分钟左右到飞机,毕竟隔着一小片海而已嘛.
199
- 入住在 Shoreditch 街附近的酒店,这附近就是伦敦的金融街,或许是大城市的人们的特性,走在这附近的街道,和国内的大城市一样,大多数人的脚步都似乎带着具体的时效目的地,你会在氛围中感受到“着急”. 也许仅仅是这个地方到气氛吧.
200
-
201
- ![IMG_7721.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-10-06/1759741792385.jpeg?raw=true)
202
-
203
- 三天的时间里,由于还要准备自己会议分享,没有办法放开的逛,打算胡乱的到处走走也蛮有意思的,古老和现代混合的建筑,高矮不一,新旧交替,错落无序. 我很喜欢城市里穿过的江河,所以我们一直走到泰晤士河(River Thamwes)边时,看着沿江两岸,晒着暖暖的阳光,迎着河边微凉的风,要是无忧无虑就好了.
204
-
205
- ![IMG_7692.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-10-06/1759742001082.jpeg?raw=true)
206
-
207
- 阴差阳错的我们登上了一个很高的可以俯瞰伦敦城的顶楼观光层,上面还有咖啡提供,人不算多,拍了两张照片也算是小插曲吧.
208
-
209
- ![IMG_7691.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-10-06/1759742426895.jpeg?raw=true)
210
-
211
- 伦敦食物上比阿姆斯特丹丰富很多,价格类似. 我甚至吃到了云南的汽锅鸡和米线. 朋友们都吐槽伦敦的交通,作为短暂的过客,我体验并没有很糟糕,就是很正常的公交车和地铁.
212
-
213
- 时间太短了,基本上什么大家来伦敦必看的地方,我都没有去好好看看,希望圣诞节那周可以如愿再来呆一呆.]]></content>
214
- <published>2025-10-06T09:28:06.524Z</published>
215
- </entry>
216
- <entry>
217
- <title>夏天意大利罗马四日游</title>
218
- <link href="https://blog.minghe.me/blog/%E6%84%8F%E5%A4%A7%E5%88%A9%E7%BD%97%E9%A9%AC%E5%A4%8F%E5%A4%A9%E5%9B%9B%E6%97%A5%E6%B8%B8"/>
219
- <updated>2025-08-14T19:34:28.147Z</updated>
220
- <id>https://blog.minghe.me/blog/%E6%84%8F%E5%A4%A7%E5%88%A9%E7%BD%97%E9%A9%AC%E5%A4%8F%E5%A4%A9%E5%9B%9B%E6%97%A5%E6%B8%B8</id>
221
- <content type="html"><![CDATA[---
222
- title: 夏天意大利罗马四日游
223
- date: 2025-08-14T19:34:28.147Z
224
- external_discussions:
225
- - platform: v2ex
226
- url: https://v2ex.com/t/1158986
227
- ---
228
-
229
-
230
- 八月,罗马的阳光,和这座城市一样,太热烈璀璨了.
231
-
232
- ![IMG_7124.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757707004060.jpeg?raw=true)
233
-
234
- 来欧洲生活也一年多了,罗马本来是我旅行城市名单的前几个,同时也是儿子心心念念一直想去看一看的城市,小朋友就是这样,看一两本关于某一个城市的书籍或者漫画,就会想去一探究竟.
235
- 由于这样或者那样的原因,一直没有成行,这个夏天终于安排上了.
236
-
237
- 从阿姆斯特丹到罗马,飞行时间两个半小时后,但是天气却差别巨大,阿姆斯特丹几乎整个夏天凉爽宜人,而走出罗马 Fiumicino 机场那一刻,我就知道这几天的旅行一定会汗流浃背的。从机场坐火车到 Termini, 然后坐地铁可以直接到我们的酒店附近。
238
-
239
- 当天下午到了酒店我们放下行李,休息好了之后,我们便出门去逛罗马了, 这次我们选择的酒店就在科尔索大道(Via del Corso)上,就在人民广场(Piazza del Popolo)边上。而且轻松步行可达的景点也很多,威尼斯广场(Piazza Venezia), 许愿池(Trevi Fountain),西班牙广场(Piazza di Spagna), 当然《罗马假日》中浪漫的西班牙阶梯也在那。
240
-
241
- ![IMG_7079.jpg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757710216692.jpg?raw=true)
242
-
243
- 白天虽然很热,晚上去还是舒服的。这天晚上我们把酒店附近的街区和景点都自然而然的走马观花完了。在罗马街头随意的走走,街边的各种奢饰品牌店和古老的历史建筑,多少让我有一种时空错乱的感觉。而身边来来往往的男女老少,东南西北的人,各种各种的语言交杂,怪不得我们会说"条条大路通罗马".
244
-
245
- ![IMG_6816.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757709626143.jpeg?raw=true)
246
-
247
- 饱饱的睡一觉之后,在酒店楼下吃完意大利早餐,就开始了**第二天**的行程是:早上我们去参观罗马斗兽场(Colosseum),下午参观梵蒂冈(Vatican City)。这是我们这次罗马之行做的唯一规划,其他的我们都顺其自然。从酒店去去斗兽场也很方便,有公交车直达,而且公交车可以也可以直接用Apple Pay,很方便。斗兽场排队入场,人很多,不过拍个十分钟也就顺利入场了,很多重要的文物介绍都有中文很英文,所以对于我们来说还是蛮友好。
248
-
249
- ![IMG_6960.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757712159565.jpeg?raw=true)
250
-
251
- > 来到欧洲生活这一年,我最大的感感受就是我的历史(特别是中国之外的历史)知识是那么的缺乏,对于文化的理解是那么肤浅,对于艺术的欣赏能力是那么的匮乏。我们人类的那么的文明成果就在身边,我却看不懂,感受不到它的美和伟大,每当此刻我就觉得很可惜。
252
-
253
- 虽然历史知识欠缺,但是看到从小就在书不断读到的场景,多少还是有点震撼,一千多年前,它的主人和人民在这里角斗娱乐,处决囚犯,狩猎表演展示罗马皇帝的权力和财富时,他们不知道如何想象超越千年之后的现在,我们所处的时代呢。
254
-
255
- ![IMG_6910.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757711422684.jpeg?raw=true)
256
-
257
- 参观完斗兽场,就到了附近的家乐福买了一些饮料,水果和面包当作午餐解决了,附近的餐厅实在是人太多了,而且我们也没有特别想吃正餐的想法,就饱喝足,我们就坐公交去往梵蒂冈了,相隔也不是非常的远,大约半个多小时。
258
-
259
- ![IMG_6999.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757712565490.jpeg?raw=true)
260
-
261
- 虽然我们购买了导游服务,但是小朋友们跟着队伍实在有点吃不消,而且讲解他们也没有什么兴趣听,所以我们跟着走了十分钟就放弃了。梵蒂冈真的需要作一些功课然后才过来参观,体感会好很多,如果历史和宗教知识都非常浅薄的话,只能像我一下,半个月之后,记忆中只剩下:馆内静谧的花园以及玄妙的旋转楼梯了.
262
-
263
- ![IMG_6969.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757712192780.jpeg?raw=true)
264
-
265
- ![IMG_7017.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757712512938.jpeg?raw=true)
266
-
267
- 由于前一天我们走的确实有点多,**第三天**我们很明智的选择了 Big Bus Tour, 这是我第一次在做观光大巴,以前在上海生活的时候,我就好多次都想坐外滩的观光大巴,就是想体验坐在大巴顶层,带着语音耳机,看着城市,流过各个历史地点的感觉。罗马的观光大巴的路线基本上把整个罗马城的各大景点都涵盖了,你可以一直坐在上面,也可以在你感兴趣的地点下车参观,然后再上车。
268
-
269
- ![IMG_7040.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757713047174.jpeg?raw=true)
270
-
271
- 惜惜和佑佑都很喜欢这种旅行观览方式,惜惜这个"社牛"当然不太可能在车上安静的听导览和看风景,很快就和后座的金发小姐姐相谈甚欢,连人家后面几天的行程都了解清楚了。观光大巴是环线运行,一圈下来大约一个来小时(如果没有记错的话),我们第一圈下来大约知道所有的经停景点,第二圈小朋友们困觉一会,然后就在博尔盖塞公园(Villa Borghese)附近下车,然后去公园走一走,公园很大也很美。
272
-
273
- ![IMG_7131.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757713422587.jpeg?raw=true)
274
-
275
- 晚上我们去吃了 Termini 附近的一家中餐,很好吃。**最后一天**因为航班是在下午比较晚的时间,所以我们就把行李寄放在酒店,然后早上沿着人民广场边上的台阶爬了一座小山,早上很凉爽,爬上了 Pincio 观景台,在街头艺术家演奏的小提琴声中,俯瞰罗马城,心情很舒畅。
276
-
277
- ![IMG_7115.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-09-12/1757714394242.jpeg?raw=true)
278
-
279
- 租个两脚蹬车,然后和小朋友一起在公园骑行,然后在博尔盖塞公园里,走了很长很长的路,直到我们离开罗马的航班时间临近。
280
- ]]></content>
281
- <published>2025-08-14T19:34:28.147Z</published>
282
- </entry>
283
- <entry>
284
- <title>四月的尾巴逛德国-柏林和慕尼黑</title>
285
- <link href="https://blog.minghe.me/blog/%E5%9B%9B%E6%9C%88%E7%9A%84%E5%B0%BE%E5%B7%B4%E9%80%9B%E5%BE%B7%E5%9B%BD-%E6%9F%8F%E6%9E%97"/>
286
- <updated>2025-04-29T11:44:58.606Z</updated>
287
- <id>https://blog.minghe.me/blog/%E5%9B%9B%E6%9C%88%E7%9A%84%E5%B0%BE%E5%B7%B4%E9%80%9B%E5%BE%B7%E5%9B%BD-%E6%9F%8F%E6%9E%97</id>
288
- <content type="html"><![CDATA[---
289
- title: 四月的尾巴逛德国-柏林和慕尼黑
290
- date: 2025-04-29T11:44:58.606Z
291
- external_discussions:
292
- - platform: v2ex
293
- url: https://v2ex.com/t/1133399
294
- ---
295
-
296
- 小朋友又迎来了一周的五月假期啦, 之前的计划实际上是去意大利的, 但是由于安排做的有点晚了,所以机票和酒店的价格都过于昂贵,所以我们换成了德国的柏林和慕尼黑, 整体的花费如下。
297
-
298
-
299
- | 项目 | | 金额 |
300
- | -------- | ------- | ------- |
301
- | 机票 | 阿姆斯特丹 → 柏林, 慕尼黑 → 阿姆斯特丹 | 612.21 欧元 |
302
- | 酒店 | 柏林 COURTYARD 三晚上 | 600.66 欧元 |
303
- | 酒店 | 慕尼黑 FOURPOINTS 四晚上 | 540 欧元 |
304
- | 火车票 | 柏林 → 慕尼黑 | 72.99 欧元 |
305
- | 餐食 | 柏林 | ~300 欧元 |
306
- | 餐食 | 慕尼黑 | ~ |
307
-
308
- > 上面都是整体价格:一个成人以及两个小朋友(9岁和10岁).
309
-
310
- ### 柏林
311
-
312
- 这是我第一次来柏林,整体的印象满不错的,和其他城市的行程其实大同小异,但感受却和游览其他欧洲城市完全不一样:带着小朋友走马观花的逛一逛博物馆,看看 Unter den Linden (菩提树下大街)沿途的建筑,参观历史悠久的柏林洪堡大学,看看画廊的涂鸦, 品尝当地的食物,这些寻常的活动,也许是柏林自带的历史文化属性,附着在这个城市的所有角落,所以感觉很奇妙,时而平静沉寂,时而开放热闹,时而规整有序,时而脏乱混杂。
313
- ![xixiyoyo.jpg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-04-29/1745955855192.jpg?raw=true)
314
-
315
- > 柏林的博物馆真的是太多了,然而小朋友们最喜欢的,玩的不亦乐乎却是间谍博物馆 (Spy Museum), 在里面玩各种间谍小游戏,玩的都不想离开.
316
-
317
- 柏林的公交系统,有点太复杂了,也许是我们没有做任何攻略,下了飞机,打开地图,捣鼓了好一会才买好票,但是找一个好一会才找到对应线路上下车点,各种 RE, U, S 以及 BUS,再加上区域相关的AB和ABC. 确实让脑袋空白🤣。 最后由于换成麻烦,中间我们直接打开 Bolt 打车去酒店.
318
-
319
- > 然后在三天的旅程里,很羞耻的被罚款了60欧,因为我想着通过 BVG Tickets app直接买票,所以下载了app之后,车来了之后,带小朋友直接上车,然后发现我还注册不了,好巧不巧,检票员来检票,能怎么办,只能乖乖的人认罚了. 后来当我到了慕尼黑,下了火车之后,我们需要做地铁(U4)到我们所做的酒店,当我们走到上地铁地方也没有看到卖票的机器,我向个中年的德国阿姨咨询,她解释道“你需要到楼上买票,一般你顺着 Exit Sign 的地方走上去,会看到机器买票,如果你到了乘车区域,而有遇到检票,你会被罚款的。” ,顺利的找到卖票机器以后,我们买了 TourCar 的三日票,30 欧元左右。12 岁以下的儿童跟着成人可以不需要购票.
320
-
321
- 柏林的食物真的比阿姆斯特丹丰富太多了,而且风味也比阿姆斯特丹更适合我,毕竟我喜欢吃肉,所以猪肘子[Maximilians](https://www.maximilians-berlin.de/)肯定得试试呀,啤酒也得喝一喝,以及传说中德国总理默尔克也爱吃的那家中餐馆[Jolly](https://www.restaurant-jolly.de/)也得试试呀,还是蛮符合我胃口。体感上觉得柏林的物价比阿姆斯特丹要合理一些,除了餐厅吃饭,酒店住宿,打车或者公共交通上,我们还去 REWE 超市买一些水果,零食,和鲜奶。基本上也比阿姆斯特丹便宜不少.
322
-
323
- 柏林的路宽更像北京比较像一些,而且城市风貌更像上海一些。这几天柏林的天气真的很好,白天走累了就在公园或者河边草地上坐一坐,晒晒舒服的阳光,很惬意。而晚上走在街头,我和小朋友们边走边给他们拿着手机,他们录制他们的[《西柚课间》](https://www.xiaoyuzhoufm.com/podcast/63f9f6ec75918da323982e2c), 微风拂树叶,我甚至有种回到上海的感觉。 我相信后面我估计还会安排一次单独的柏林旅行,来这个城市好好的住上一段时间.
324
-
325
- ![tree.jpg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-04-29/1745955819583.jpg?raw=true)
326
-
327
- ### 慕尼黑
328
-
329
- 从柏林到慕尼黑的火车其实还是蛮快,四个多小时,和从北京到上海差不多的时长。车上也可以点咖啡和一些食物,我们吃点零食,喝个咖啡,鞋垫文档,惜惜和佑佑看看书,睡睡觉,很快也就到了慕尼黑.
330
- > 发生了一个小插曲,我买票的时候没有注意自己买的票是二等座,而上车的时候也没有注意自己竟然做的一等座车厢,直到检票人员告诉我才知道。
331
-
332
- 下了火车,我们就直接去坐地铁去酒店了,慕尼黑的公共交通系统似乎比柏林简单一点?而且买票直接就可以在手机上购买,当然也可能是我们慢慢熟悉了,我们在穆尼黑的几天全都乘坐公共交通来进行旅行,S 和 U 的地铁,城市的公共汽车,都很方便。我们房间在酒店的高层,可以看到慕尼黑的夜晚的点点灯光。
333
-
334
- ![IMG_5903.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-05-21/1747859232104.jpeg?raw=true)
335
-
336
- 饱饱的睡了一晚上之后,第二天公交车大谷物市场附近下车,窜梭在谷物市场中,看着卖花,卖食物,卖工艺品的摊铺,阳关也很好,人们都悠闲的吃吃喝喝。我们就慢悠悠的走着,很快就到了玛利亚广场,很巧的时候,正好赶上了早上 11:00 左右的木偶钟表表演,和人群一起观看着木偶表演。
337
-
338
- ![IMG_5930.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-05-21/1747859255454.jpeg?raw=true)
339
-
340
- 下午吃饱喝足了之后,我们简单的看了看慕尼黑市政厅,不过真的没有留下什么特别的印象,之后我们就去参观慕尼黑皇宫了,直接现场购票即可,建议带上语音导览。
341
-
342
- > 在欧洲也去了好多宫殿,博物馆,美术馆等,其实很少看到服务人员是中国人,甚至华人面孔都很少,而慕尼黑皇宫语音导览服务处的两位服务人员是中国同胞,多少还是增加一点熟悉感。
343
-
344
- ![IMG_5955.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-05-21/1747859267584.jpeg?raw=true)
345
-
346
- 整个皇宫参观过程体验很好,人不是那么多,路线设计也很好,整体的建筑,馆内的藏品,家具摆设,在语音导览中都有很好的介绍,而且不是干涩的介绍,有较为详细的背景介绍,所以听起来很轻松和有趣很多,整个过程比我参观马德里皇宫的感受好太多了,而且马德里皇宫我们还是有导游带着的,但是感受却一般, 可能还是当时跟不少人,而且导游的英文和讲故事的方式傻姑娘没有达到预期吧。
347
-
348
- 第三天我们去宝马世界 (BMW World) 和宝马博物馆 (BMW Museum) 参观,各种汽车还是蛮有趣,汽车迷如果到了慕尼黑还是可以去看看的,宝马历史很久,车子很酷。
349
-
350
- > 最近好喜欢 MINI COOPER,希望今年可以开着去旅行.
351
-
352
- ![Screenshot 2025-05-21 at 22.24.07.png](https://github.com/metrue/Cofe/blob/main/assets/images/2025-05-21/1747859282989.png?raw=true)
353
-
354
- 然而这天让我最印象深刻却是英国公园(Englischer Garten), 是德国慕尼黑最著名的城市公园之一,也是在世界上最大的城市公园之一,比纽约的中央公园还大。这是我见过的人最多的公园,我曾经以为其他国家公园再热闹,也一定比不上我们中国的公园热闹。到了慕尼黑的英国公园,我才知道,公园长满人,原来是字面意思的长满人。而且人们真的好Chill。
355
-
356
- 第四天,小红书上之前联系好的小姐姐带我们参观两所德国著名大学:慕尼黑大学和慕尼黑工业大学。有熟人带着游览大学,体验就好很多了,校园走走,介绍一些历史,教学楼参观参观,分享一些趣事,小朋友也喜欢问这问那的,互动参观过程就会好玩一些,可惜惜惜和佑佑走不了太多路,不然可以去更多校区。
357
-
358
- ![IMG_6216.jpeg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-05-21/1747859294930.jpeg?raw=true)
359
-
360
- 慕尼黑整体玩几天下来,感受没有像柏林一样给我一种:我想我一定安排个时间再来住上一段时间的想法。也许是我没有感受它的独特性,而柏林似乎散发一种特别的Vibe,然后恰好我比较喜欢.
361
-
362
- 不过如果问惜惜和佑佑,这次德国旅行,什么最值得回忆,他们一定会说:游泳。因为他们两同时在酒店的游泳池学会了游泳。我断断续续教他们游泳有一些时间,但是突然间,两人在到酒店第二天晚上去游泳(我们还是当天去迪卡侬买的泳衣泳裤的),我跟他们玩着玩着,突然就掌握, 很奇妙。而且还和当地的小朋友一起做游泳游戏,聊的很开心。
363
-
364
- ]]></content>
365
- <published>2025-04-29T11:44:58.606Z</published>
366
- </entry>
367
- <entry>
368
- <title>二月葡萄牙游记</title>
369
- <link href="https://blog.minghe.me/blog/%E4%BA%8C%E6%9C%88%E8%91%A1%E8%90%84%E7%89%99%E6%B8%B8%E8%AE%B0"/>
370
- <updated>2025-02-25T19:42:53.549Z</updated>
371
- <id>https://blog.minghe.me/blog/%E4%BA%8C%E6%9C%88%E8%91%A1%E8%90%84%E7%89%99%E6%B8%B8%E8%AE%B0</id>
372
- <content type="html"><![CDATA[---
373
- title: 二月葡萄牙游记
374
- date: 2025-02-25T19:42:53.549Z
375
- external_discussions:
376
- - platform: v2ex
377
- url: https://v2ex.com/t/1115332
378
- ---
379
-
380
-
381
- 小朋友又迎来了一周的春假,十二月的冬假,去西班牙的巴塞罗那和马德里,小朋友蛮开心的,详见上一篇的博文 “[西班牙七天的旅行](https://blog.minghe.me/blog/%E8%A5%BF%E7%8F%AD%E7%89%99%E4%B8%83%E5%A4%A9%E7%9A%84%E6%97%85%E8%A1%8C) ”,以及我参与的小朋友们自己的小播客 “​​[西柚课间| 小宇宙 - 听播客](https://www.xiaoyuzhoufm.com/podcast/63f9f6ec75918da323982e2c) ”. 这次我们选择葡萄牙的波尔图 Porto 和里斯本 Lisbon, 短暂离开荷兰的冬天,去享受一下阳光吧.
382
-
383
- 几乎不太需要什么规划,两个城市都是热门欧洲旅行目的地,从阿姆斯特丹出发飞机直达,如果有什么需要提醒的:那就早点订机票和酒店吧,哪儿的旅行不需要早点订机票和酒店呢?早定早安心,而且省钱. 这次和上次的交通方式和酒店方案类似。
384
-
385
- ### 交通
386
-
387
- * 阿姆斯特丹 → 波尔图: 荷兰航空,不到三个小时.
388
- * 波尔图 → 里斯本: 火车, 接近三小时
389
- * 里斯本 → 阿姆斯特丹: 荷兰航空,三小时.
390
-
391
- ### 酒店
392
-
393
- 我出行还是不习惯使用 Airbnb, 所以一般都选择酒店,而且每次都是家庭出行,所以需要家庭套房,所以价格也会相对高一些,不过这次价格相对可控。
394
-
395
- 在波尔图, 我们选择了 Vincci Hotel,在 Booking 上的评价其实还不错,这个酒店就在杜罗河边,不过整体设计中规中矩,没有太多惊艳的地方,不过早餐还是不错的,加上税8欧元的早餐还是蛮丰盛的,我们吃的都很满意. 在里斯本,我们选择了 Moxy Hotel,这酒店经济年轻,家庭房也很凑合,其实这个酒店不合适有钱的商务人士,也不适合真正想在酒店里玩耍的亲子需求的家庭,但是适合我们这样,简简单单,干干净净,年轻且些许时尚的“年轻”家庭.
396
-
397
- ## 波尔图
398
-
399
- 落地波尔图,小朋友们绝对好像回到爷爷奶奶家,气温很温暖。我们坐601 公交车从飞机场去酒店,一共27站,一路上对这个城市有了一些初印象:小城市,很多地方像中国的南方小县城,路边灰土灰土的,但是有山有树,上上下下,很有层次。下了车,沿着一条弯曲,有些地方甚至很狭窄的下山路,走到杜罗河边就到我们的酒店了
400
-
401
- ![P0.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514356850.webp?raw=true).
402
-
403
- 酒店入住之后简单收拾,然后休息到傍晚,就打车到市中心去找饭店吃饭了,饭店一般我直接都在 Google Map 上直接搜索,然后看着不错就直接去,波尔图的第一天晚上选择的这家饭店就在河边,我们坐在室外,天气不错,看着路边人们走来走去。我们点的很常规的食物,除了生蚝有点不合适(因为它真的是生的,我目前还是受不了生的腥味),其他都比较正常,海鲜饭,蒜香虾等都不错。
404
-
405
- 令人开心的是晚餐时候的邻桌是一对爱尔兰的夫妇,有五个小孩,最小的已经十五岁了,所以他们有大把的时间出来玩,不过除了之前到过香港,中国其他城市没有来过,不过他们很喜欢中国美食。我们聊的很开心,惜惜(女儿)滔滔不绝和他们分享各种事情,他们也很耐心和捧场,过程中他们也“分享”了很多英国和美国之间的各种Beef, 我说我女儿现在在说话的时候用很多 “like”,她说小朋友现在确实特别爱用 “like”, 而且受到美国英文习惯的影响非常大,然后列举好多中美英文差异的地方,从食物到足球,顺便还炫耀一下就算是大学,英国质量也比美国好(哈哈哈)。最后还给我们推荐了不少的英国食物。
406
-
407
- ![P1.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514382391.webp?raw=true)
408
-
409
- 吃完晚餐,沿着河边走走,正好听到街头艺人正在唱 “Hey, Jude”, 全场氛围很棒,买了一份炭烤栗子,边吃边逛回酒店。
410
-
411
- ![P2.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514398405.webp?raw=true)
412
-
413
- 第二天早上有点小雨,在酒店吃完早餐,我们就去打车到狮子喷泉,本来打算去波尔图大学看看一下,没想到就是一栋楼(后来听说只是其中的一个办公楼),路过莱罗书店,但是排队的人实在是太多了,所以我们就去买了伽莫修道院参观了。
414
-
415
- ![P3.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514422417.webp?raw=true)
416
-
417
- 我个人到异国他乡旅行,如果当地的导游服务不是很贵,我一般都喜欢购买导游服务,这次波尔图也一样,在 Booking 上买一个的导游服务,很便宜,一欧元一个人。英文讲解,带你走遍十几个主要景点。小哥是都柏林人,讲的还是挺有激情的,如果懂一些欧洲历史,听着可能还更好玩一些,而且可以一起讨论,蛮有意思的.
418
-
419
- ![P4.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514435622.webp?raw=true)
420
-
421
- 总共十几个人的团,团中还有另外一个中国小哥,简单聊了聊,碰巧他之前也在荷兰莱顿生活过。导游小哥带着我们三个多小时,走了十几个景点。 Fonte dos Leões ➝ Praça Gomes Teixeira ➝ Edifício da Reitoria da Universidade do Porto ➝ Igreja do Carmo ➝ Livraria Lello ➝ Torre dos Clérigos ➝ Antiga Cadeia da Relação ➝ Monumento a Dom Pedro IV ➝ São Bento Railway Station ➝ Rua das Flores ➝ Miradouro da Vitória ➝ Porto Cathedral (Sé Catedral) ➝ Praça da Ribeira ➝ Ponte de Dom Luís I
422
-
423
- ![P5.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514453577.webp?raw=true)
424
-
425
- 后来由于小朋友们实在是累了,所以我们在火车站那一站就放弃了,然后打车回酒店休息了.
426
-
427
- 晚上我们到一个很火的餐厅,排队了一个多小时,不过最后吃的还算满意,而且他们的服务也很到位,我们一家人吃的都很开心。
428
-
429
- 第二天是自由的一天,睡到自然醒,然后乘坐酒店门口的公交车,直接到 Matosinhos的海边,小朋友在沙滩玩了很久。直到饿了才打车回到市区吃午餐,然后在城市走走看看,波尔图主教座堂附近都值得走一走,最后徒步走路易一世大桥,走到另一边,就是一个小山坡草地,大家都坐在草地上,看着波尔图的城市风景,迎着夕阳,听着街头艺人的音乐,直到我们晚餐时间。
430
-
431
- ![P6.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514484399.webp?raw=true)
432
-
433
-
434
- 万万没有想到,很少生病的惜惜竟然半夜发烧了,第二天早上还是感觉不是很舒服,早餐也吃的不多,因为我们下午一点多就要坐火车出发去里斯本了,本来打算早上再去逛一逛老城区,但是惜惜不舒服,所以计划就改成了,小朋友们在酒店休息,妈妈收拾行李,我去买退烧药。在葡萄牙买药很简单,简单的描述病情和小朋友基本信息,药师就会推荐相应的药物,并且询问我是否介意含有布洛芬。
435
-
436
- 买药的路线是一条僻静的上下山小道,是我们来时的路。
437
-
438
- ## 波尔图火车到里斯本
439
-
440
- 从波尔图到里斯本的火车,速度倒是还行,和国内高铁差不多,但是平稳程度和国内的高铁差太多了,惜惜在一半的时候在车上呕吐了,我只能和列车员说抱歉,列车员也是见怪不怪了,说这是很常见的。旁边的乘客很友好的给我们一些纸巾,甚至拿出了药物给我们,但是当我说她稍微有点发烧,而身后的弟弟有点咳嗽(波尔图的海鲜饭真的好咸),他们就默默的带上了口罩,显然是怕流感了。
441
-
442
- *事实是确实流感了,我回到了阿姆斯特丹的第二天我就全身酸痛*。
443
-
444
- ## 里斯本
445
-
446
- 从波尔图到里斯本,有点点进城的感觉,火车站到酒店直接打车即可,在葡萄牙基本上可以实现打车自由,自从到欧洲生活,感觉忘记了自己也曾经有几个消费自由(比如全家自由,优衣库自由,外卖自由),到酒店了之后,已经五六点了,所以找了附近一个蛮火的餐厅,但是其实感觉一般.
447
-
448
- 其实 Moxy Hotel 早餐看上去还可以,成人单价14欧元,不算太贵,儿童基本上酒店都是免费吃早餐的,但是惜惜和佑佑去参观了早餐的食物之后,不是很喜欢,所以我们决定在其他地方去吃早餐,但是 Google Map 搜了半天都看不到合适,最后在酒店旁边的 Brunch 店解决了,十几欧的价格,三明治,烤吐司,两杯咖啡和一杯果汁,其实也蛮不错的.
449
-
450
- 第一天的站是 Torre de Belem (贝伦塔),葡萄牙航海时代的产物,四五百年的历史了,古老和些许的壮观,在海水的冲刷中又带些落寞的沧桑。人不少,我坐在草地边晒太阳,惜惜,佑佑和妈妈在水边玩耍,抓了几只小螃蟹和漂亮的贝壳。
451
-
452
- ![P7.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514541224.webp?raw=true)
453
-
454
- 欣赏完贝伦塔,继续沿着 Tejo River 往前走,就可以到达航海纪念碑了,碑上的三十三位航海时代的重要人物,可以一略葡萄牙在航海时代的辉煌,目前也是一座博物馆,可购票入内参观,不过这次不巧,博物馆闭馆,要到三月份才开放。
455
-
456
- 航海纪念碑继续前进不到三四百米即是热罗尼摩斯修道院(Mosteiro dos Jerónimos), 本来打算购票进去参观的,从外部看只是非常的壮观宏伟,但是小朋友对修道院不感兴趣,所以就放弃了。而且排队较长,所以带小朋友去 Museu de Marinha 的餐厅上个洗手间之后,坐在修道院前的小公园的石凳上,听着美妙的音乐,吃着美味的午餐,享受阳光,很惬意。
457
-
458
- ![P8.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514557661.webp?raw=true)
459
-
460
- 吃饱喝足,休息好之后,我们公园走一走,就打车去里斯本大学了:去任何城市旅行,去大学参观是常规项目。里斯本大学,说实话,才几天过去,但是其实没有留下太多印象,因为是在不懂这个大学,而且也没有整个过程也没有眼前一亮的地方,所以我们想以后我们去大学参观一定找一个对学校熟悉的人来当导游。
461
-
462
- ![P9.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514568788.webp?raw=true)
463
-
464
- 逛完大学,我们回酒店休息好了之后,就找了一家韩国烤肉店,因为好几天都吃的葡萄牙本地的餐食,想换个口味,没想这个决定让我们付出了惨痛的代价,第二天早上,佑佑练习的呕吐,而且轻微的发烧,显然是食物中毒了,我们因为呕吐完了之后应该就慢慢恢复了,但是早餐佑佑也吃很少,休息好几个小时,还是感觉不舒服,所以显然旅行计划只能改变,选择一些不费劲的方式:最后我们选择了坐有名的28路小黄车游览一下里斯本. 不过因为有一下午的时候,所以我先带着小朋友在 Martim Moniz Square 坐着晒太阳,惜惜还和一个大叔拿了鸟食喂了一会儿鸽子。不过偶尔就看到有人在广场的大叔底下小便,蛮大煞风景的。
465
-
466
- ![P10.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514582240.webp?raw=true)
467
-
468
- 28路小黄车还是可以坐一坐的,不过排队需要好一会,不过叮叮当当坐着,浏览着古老的城市,还是挺有感觉的,正好它的终点站是卡蒙斯广场(Praça Luís de Camões),是里斯本市中心的一个著名地标,向葡萄牙伟大的诗人 路易斯·德·卡蒙斯(Luís de Camões) 致敬. 我也顺便在那附近的一个药店买给佑佑一些药物,在那儿坐着看看人群,聊聊天,然后我们就会酒店了,晚上去吃了一家中餐,味道很地道,而且佑佑吃了一整份的汤包,以及麻婆豆腐和一点米饭,些许恢复体力。
469
-
470
- ![P11.webp](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-25/1740514592708.webp?raw=true)
471
-
472
- 第三天中午就要坐飞机会阿姆斯特丹了,所以早上就睡到自然醒,然后打车直接去机场,发现葡萄牙的 Bolt 司机比西班牙的司机友善很多,他们会主动的帮你拿行李,微笑服务,而且英文普遍还行。
473
-
474
- ## 后记
475
-
476
- 这次绝对不是那么让人享受的旅行,但是意料之外的事情,也让我们的旅行记录更加地丰富,经过这次旅行的生病,我们得到两个教训:出门带点药,以及不要去吃不能确保安全的食物(比如烤肉)。
477
-
478
- 最近正在惜惜和佑佑讨论下次旅行目的地,在英国和意大利之间角逐,期待下次旅途.
479
- ]]></content>
480
- <published>2025-02-25T19:42:53.549Z</published>
481
- </entry>
482
- <entry>
483
- <title>西班牙七天的旅行</title>
484
- <link href="https://blog.minghe.me/blog/%E8%A5%BF%E7%8F%AD%E7%89%99%E4%B8%83%E5%A4%A9%E7%9A%84%E6%97%85%E8%A1%8C"/>
485
- <updated>2024-12-24T19:01:37.622Z</updated>
486
- <id>https://blog.minghe.me/blog/%E8%A5%BF%E7%8F%AD%E7%89%99%E4%B8%83%E5%A4%A9%E7%9A%84%E6%97%85%E8%A1%8C</id>
487
- <content type="html"><![CDATA[---
488
- title: 西班牙七天的旅行
489
- date: 2024-12-24T19:01:37.622Z
490
- external_discussions:
491
- - platform: v2ex
492
- url: https://v2ex.com/t/1100548
493
- ---
494
-
495
-
496
-
497
-
498
- 如果你在欧洲的公司工作,十二月份的很多时候,如果安排多人的会议,大概率你是找不齐所有人的,因为十二月份是大家休假的集中期,所以有些公司也会在这个期间有一个长达两三周的
499
- `Change Freeze`. 我也选择在这段时间休假,不过休假旅行的地点是小朋友们定的,姐姐(惜惜)和弟弟(佑佑)最终选择了西班牙:巴塞罗那和马德里。
500
-
501
- > 本来也想着马德里之后去葡萄牙的里斯本和波尔多,然后再回阿姆斯特丹,但是想着虽然当前虽然天气很好,但是可能户外游泳还是有点冷,而且第一次一个人带着姐姐和弟弟两人旅行,所以就想等着妈妈到了之后,春天的时候再安排一次。
502
-
503
- ## 准备和出发
504
-
505
- ### 交通
506
-
507
- 选定了城市之后,一切就很简单了,我来负责购买机票和预定酒店,惜惜和佑佑通过看Youtube的相关频道来决定我们的旅行攻略。从阿姆斯特丹到巴塞罗那的航班很多,我们当然是选择便宜的航班出行了,选了几家所谓的经济航班,最后我们我们的交通方案是:
508
-
509
- * 阿姆斯特丹到巴塞罗那, 乘坐Vueling (伏林航空),三个人的价格大约三百欧元。
510
- * 巴塞罗那到马德里,乘坐火车,成人价格是六十五欧,儿童是七欧。
511
- * 马德里回阿姆斯特丹,乘坐AirEuropa, 三个人的价格不到三百欧元。
512
- * 城市内的交通,公交车或者出租车都很方便。
513
-
514
- 我们三个人轻装出行,各自背自己的背包,而且我们的背包都符合航班的免费行李额度,一般是 `30cm * 40cm * 50cm`.
515
-
516
- ### 酒店
517
-
518
- 由于带小朋友旅行,加上我本身对民宿也没有啥选择经验(唯一一次住Airbnb还是七八年前出差洛杉矶的时候公司帮忙预定), 所以无论在国内还是国外旅行,我们都是住酒店,一般的策略是如果需要定三家房间以上的,比如家庭旅行带着父母,妹妹一家一起的,我就会选择经济一些的连锁酒店比如全季,这些酒店体验也很不错,标准化的流程和设施,很省心也很省钱. 如果人少的旅行,选择就会宽裕一点,而这次我们分别选择了:
519
-
520
- * 巴塞罗那的 SB Lacica hotel, 离沙滩很近,早餐也不错,公共交通也超方便。
521
- * 马德里的 Radisson Blu,早餐种类偏少,但是离各个景点都是步行可达,而且周边无论餐厅,街区,店铺非常丰富。
522
-
523
- 两家酒店价格有些许区别,不过都在两百到三百欧之间, 不过惜惜和佑佑一致的结论是更喜欢 Radisson Blu, 他们觉得这个酒店设计品味和服务更好,比如惜惜说浴室的开关和淋浴头的分离让她不会不小心淋到水,前台办理入住有专门的凳子,以及糖果和饮料。小朋友的视角确实很独特,当然我本人也更喜欢 Radisson Blu。
524
-
525
- ### 相关证件
526
-
527
- 我荷兰居留卡都带在身上,事实证明也是必要的,发现有的地方需要看居留卡,有的地方则只需要护照即可。
528
-
529
- ### 其他
530
-
531
- 搞定了交通和酒店之后,其实其他的东西没有什么需要特别注意的了,比如,
532
-
533
- * **支付**,欧洲基本上都支持移动支付,我Apple Pay绑定了ABN的银行卡,我在欧洲所有的支付基本上都是直接刷手机, 不用对这二维码扫来扫去,也挺方便的。
534
- * **公交车**, 也直接上车刷手机(绑定了银行卡,应该Visa也可以)。
535
- * **出租车**,我一般都是直接在路边招手拦车,下车手机支付.
536
- * **网约车**,Uber 和 Bolt 都是可以用的,但是我很少用.
537
- * **地图**,Google Map 确实离不开,因为无论是去景点,还是选餐厅,都离不开它。
538
-
539
- ## 巴塞罗那
540
-
541
- * **阳光和沙滩**
542
-
543
- 阳光很灿烂,感觉真的好温暖,其实看数据,气温也就是比阿姆斯特丹高不大十度,但是体感温暖舒适很多,而且沙滩很干净,海水很蓝,人也不多,穿着简单的衣服,躺在沙滩上,看着小朋友玩沙玩水,看着人们玩沙滩排球。还蛮惬意的.
544
- ![Beach](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-23/1734991833894.jpeg?raw=true)
545
-
546
- * **圣家堂(Sagrada Familia)**
547
-
548
- 我自己艺术修养很浅,接近于零,但是当看到这壮观的建筑,还是感觉到强烈的震撼,在外面观赏,建筑高耸入云,无数个形态各异,而又和充满故事的雕像,就算像这样没有太多西班牙以及宗教知识的人也带来强烈的视觉和心里冲击。
549
- ![DF088B9C-5914-4798-9655-6686B5DDF01B_1_105_c.jpeg](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-23/1734993280313.jpeg?raw=true)
550
-
551
- 走进里面,宗教色彩斑斓的窗,沿着高高的柱子往上,看到是设计精细的各种形状,好吧,没有艺术功底确实找不到合适的描述方法。只能说"我虽然看不懂,但是我大受震撼"。
552
- ![FAFB421B-6AC5-43B7-8F82-DC67150DCF18_1_105_c.jpeg](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-23/1734993317984.jpeg?raw=true)
553
-
554
- * **毕加索博物馆(Museu Picasso)**
555
-
556
- 这个博物馆展示了毕加索各个时期的各种作品,门票小朋友免费,大人十来欧,我们租了导览器,这样能够让自己多少了解一下作品背后的故事,不然确实对于我这样的绘画和艺术零基础的人来确实也只是看看颜色了。这里展出了超级多的毕加索作品,也算大饱眼福了,当然小朋友们看了大部分之后,就走不动了,所以其实我们并没有完全看完所有的作品。
557
- ![8498516D-1DBD-4A44-96EB-9C96597F395F_1_105_c.jpeg](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-23/1734993411252.jpeg?raw=true)
558
-
559
- * **凯旋门**
560
-
561
- 凯旋门是我们离开毕加索博物馆,打算去吃完饭的时候路过,我们坐在草地上边,惜惜和佑佑喂了好一会鸽子,甚至还有一些鹦鹉,蛮有意思的。凯旋门本身没有太多让我印象深刻的地方,如果不是佑佑告诉我,我都不知道巴塞罗那也有凯旋门,以为只有巴黎有凯旋门。
562
-
563
- * **巴塞罗那大学(Universitat de Barcelona)**
564
-
565
- 我们养成了旅行习惯,那就是每到一个城市旅行,我们都会去当地的大学校园去参观参观,所以来到了欧洲之后,我们参观了不少大学,不过目前主要还是局限在荷兰的大学,像代尔夫特理工大学,阿姆斯特丹大学,阿姆斯特丹自由大学,来顿大学等等。希望随着探索越来越多的欧洲城市,我们可以去参观更多的大学. 我们专门安排了一个早上来参观巴塞罗那大学,确实也是值得的,很美的大学。偶遇了一家三口华人也在参观,小朋友还分发一些糖果给惜惜。
566
- ![3194C881-C139-4791-9E76-F36D6BCE055D_1_105_c.jpeg](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-23/1734993562660.jpeg?raw=true)
567
-
568
- * **庞培法布拉大学(Universitat Pompeu Fabra)**
569
-
570
- 在巴塞罗那的最后一天,因为下午的火车去马德里,饱睡一觉之后,吃好早餐之后,所以早上有几个小时的时间,我们决定去一趟UPF, 我们跟着Google Map 去到写着UPF的一个栋看着超级古老的建筑时候,惜惜走进去问了一下工作人员,他们说这里是办公楼,目前不提供参观,不过工作人员很友好的走到外面,拿着一张他们的校园地图给我讲解,推荐我们去附近的一个校区参观。我们按照他给的地图,走了大约二十分钟,终于走到了,不过这个校区较小,我们逛了一会就打车去火车站了。
571
-
572
- ## 马德里
573
-
574
- 从巴塞罗那来马德里的火车大约是两个小时十来分钟,还是非常的快的,马德里的火车是"疯狂动物城"的原型地,但是其实我们没有停留来参观。而且发生了一个神奇的事情,当火车停下来,我们下了火车之后,我打开 Google Map 打算去酒店的时候,看到距离竟然是 120+ 公里,我一下惊呆,难道我下错车站了么?所以赶紧去到售票机去看看马德里的火车票,翻了一会竟然找不到对应的火车站,问了一下傍边的人,他们都不太会英文,后来看到一个华人面孔的哥们,赶紧找他咨询,他中文还凑合,才发现我们并没有下错,这里就是马德里的火车站,我这时候再打开 Google Map 一看,发现这时候距离到酒店就900米,怎么又正确了呢,我说怎么找不到火车站呢,原来我所在位置没有啥问题,可能是之前手机 GPS 出现了一些问题.
575
- ![3F99D917-1D45-4591-957B-1952C28371A8_1_105_c.jpeg](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-23/1734993893285.jpeg?raw=true)
576
-
577
- 来到了马德里,体感上确实比巴塞罗那凉一些,走到酒店的一路上,马德里给我的初印象还是不错,街道干净,交错的小巷子,人们喝酒聊天,氛围也很好。
578
-
579
- * **普拉多博物馆(Prado Museum)**
580
-
581
- 事实证明,这个酒店定的很成功,一觉睡到天亮,吃完早餐我们就出发去普拉多博物馆,距离非常的近,步行几分钟就到了,普拉多博物馆是西班牙最大的美术馆,普拉多拥有的杰作数除了涵盖欧洲所有流派和所有名家之外,还几乎囊括了哥雅的全部精品。博物馆确实很大,我们也购买了语音导览,跟着导览图听着语音介绍,整体体验还是可以的,参观的人不少,所以有的作品前面会站的很多人。每次参观艺术作品,我都总恨自己的艺术修养怎么那么低,一方面在整个接受教育的生涯中,没有接受过系统的艺术教育,另一方面自己也没有花时间去阅读艺术书籍学习提高自己的艺术鉴赏能力。真的惭愧呀,希望未来可以多花一些时间在这些方面,做一个会欣赏的人. 普拉多博物馆是不允许拍照的,所以没有留下什么照片,仅仅在管外拍几张。
582
- ![1E60F4FC-3E69-4FC3-84CC-B9F0717B83D9_1_105_c.jpeg](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-24/1735068363518.jpeg?raw=true)
583
- * **丽池公园 (EI Retiro)**
584
-
585
- 从普拉多博物馆走几分钟就到丽池公园,这个公园听说是皇室园林,不过也对外开放了一两百年了,园子还是蛮大的,没事坐在晒晒太阳,喂喂鸟,喝喝酒,聊聊天,听艺人演奏音乐,看人们跳跳舞,还是蛮享受的。
586
- ![69179880-1043-4B41-A7B8-097D4DE2CB18_1_105_c.jpeg](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-23/1734994064317.jpeg?raw=true)
587
-
588
- * **马德里皇宫**
589
-
590
- 马德里皇宫的门票,最好还是提前一些买比较合适,我提前几天看已经没有票,最后我是在 Booking.com 直接买了 skip line with guide 的票,不过导游的英文需要竖起耳朵来听才能听懂,所以我听着还勉强能够跟得上他的讲解,惜惜和佑佑听起来就有点费劲,好在整个皇宫导游带着游下来,大约也就一个小时。不过皇宫本身还是值得一看的,虽然和我们故宫比起来规模还是小很多的,但是也是非常辉煌气派, 而且装饰风格和设计细节也很大不同, 值得一逛。
591
- ![99EDFAD2-0AEB-43D4-96D7-80FBCB8BAA72_1_102_o.jpeg](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-23/1734994128679.jpeg?raw=true)
592
-
593
- * **康普顿斯大学(Universidad Complutense de Madrid)**
594
-
595
- 作为西班牙最知名的大学,我们也是安排最后一天早上来参观,大学位于马德里大学城,和国外很多大学一样,康普顿斯大学其实也没有所谓的大学校门,但是你可以看到各个学院的名字,清晰的知道是哪儿, 我也没有走到作家三毛曾经就读的文学院,我们也是走马观花的走了走,就打车去机场,准备回阿姆斯特丹了。
596
- ![C601AB53-55F4-42FF-B3B5-CCA28000E15A_1_102_o.jpeg](https://github.com/metrue/cofe/blob/main/data/assets/images/2024-12-23/1734994189257.jpeg?raw=true)
597
-
598
- ## 那些有意思的瞬间
599
-
600
- * **指挥大爷?**
601
-
602
- 在排队安检进入候机厅的时候,惜惜和佑佑也不知道什么时候学习的荷兰语生日歌曲,边排队边唱了起来,服务员大爷主动当起乐队指挥,双手舞动了起来,还蛮有意思的。
603
-
604
- * **走错了航站楼?**
605
-
606
- 从康普顿斯大学打车去马德里机场的时候,目的地写成了Terminal 4, 但实际上是 Terminal 3, 其实路上快到的时候我就发现了自己写错了,但是司机大叔英文真的是一句都不懂,到了 Terminal 4 之后,我看从 Terminal 4 到 Terminal 3 需要10几分钟的免费大巴,五分钟一趟,我看离起飞也就是35分钟,肯定是来不及,从第一辆车下来之后,我赶紧拦了另外一辆车,还好这个小哥们年轻,能说一些英文,在确定了我走错了航站楼之后,让我们上车了,到了 Terminal 3 之后,尴尬的事情是我没有任何现金,而他也没有收钱的机器,他本来也无所谓了,我说我有Uber, Bolt, Uber 或者 Paypal都可以,他说那你用 Paypal 转吧,我说转多少你说个数,他说随意就好哈哈哈。最后幸好 Terminal 3 没有像虹桥或者浦东的航站楼那样需要走很久才到登机口,我们过了安检,走几分钟就到了登机口了,也正好大家在排队登机,一切刚刚好。
607
-
608
- * **录播客**
609
-
610
- 因为我很爱听播客,所以小朋友们潜移默化的也对播客这种内容也有些概念,所以当我提议可以录一个播客来记录他们的旅行,他们还是蛮兴奋的,我们三个人一起很快就确定了名字: ["西柚课间"](https://www.xiaoyuzhoufm.com/podcast/63f9f6ec75918da323982e2c). 前面三期我帮他们串串场,最后一期他们两单独录制了,听着还挺开心的。
611
-
612
- ## 最后
613
-
614
- 第一次和两个小朋友单独旅行,小朋友确实长大,也学会简单的做一点准备,学会在机场大屏幕寻找自己的航班,航站楼,和登机口,也学会慢慢欣赏城市风景和艺术作品。佑佑和惜惜已经开始规划春假的旅行了,瑞士,德国,和意大利之间选择,期待中.
615
- ]]></content>
616
- <published>2024-12-24T19:01:37.622Z</published>
617
- </entry>
618
- <entry>
619
- <title>上海到阿姆斯特丹</title>
620
- <link href="https://blog.minghe.me/blog/%E4%B8%8A%E6%B5%B7%E5%88%B0%E9%98%BF%E5%A7%86%E6%96%AF%E7%89%B9%E4%B8%B9"/>
621
- <updated>2024-09-27T17:56:10.267Z</updated>
622
- <id>https://blog.minghe.me/blog/%E4%B8%8A%E6%B5%B7%E5%88%B0%E9%98%BF%E5%A7%86%E6%96%AF%E7%89%B9%E4%B8%B9</id>
623
- <content type="html"><![CDATA[---
624
- title: 上海到阿姆斯特丹
625
- date: 2024-09-27T17:56:10.267Z
626
- ---
627
-
628
- ## 前言
629
-
630
- 从上海来到阿姆斯特丹也一周了,两个小朋友,两个大人,一个决定,年初做这个决定,也曾有过很多迟疑,然而当决定做好了之后,两个相隔万里的城市,也仅仅是一张飞机票的距离。
631
-
632
- ![ticket](https://github.com/metrue/picx-images-hosting/raw/master/Screenshot-2024-07-21-at-13.58.18.7w6psuu1cf.webp)
633
-
634
- ## 决定
635
-
636
- 我很早就有在小朋友们的小学阶段,带他们去国外生活一段时间的想法,一方面是自己想去体验世界,一方面也是想让小朋友在小时候能感受不同的文化氛围。而现在是一个很好的时机,姐姐三年级,弟弟一年级,多少能自己照顾点自己,而同时又能相互陪伴。
637
-
638
- 当然更重要的是我和老婆的决定,我们两个人都在上海呆十年左右,工作暂时还算轻松稳定,有房无贷,我们两对于物质也没有啥过高的要求,但是你知道,在上海,无论是否有生活压力,每天的日程都是比较紧凑的。对于小朋友的教育,虽然心里有所期待,但是整体不是虎爸虎妈,健康快乐,健全人格为主。对于生活环境,我们都是小镇青年,从小学,中学,大学,到工作,也不断的从一个城市到一个城市,基本上对于各种环境也有一定的容忍度,自认为可以适应各种环境变化和文化差异。
639
-
640
- 不过显然这还是一个不小的决定,而且这个决定会给很多人带来变化:
641
-
642
- **自己**: 还是原来的公司,原来的团队,原来的工作内容,只是换一个城市,需要去适应新的工作氛围,需要重新去经营和老板,以及身边的同事的关系。
643
-
644
- **小朋友**: 他们需要去适应新的学校,新的教育方式,结交新的小朋友,对他们来说也是很大的挑战。但是和他们沟通之后,他们也拥抱我们的决定。
645
-
646
- **伴侣**: 而我老婆也同样需要面对的新的挑战,陌生的环境,而且如果辞去当前的工作,意味她需要全部从零开始,她很坦白的和她老板坦白自己的想法,她老板也也很理解和宽容,可以不用辞职,去阿姆斯特丹远程工作两个月,尝试自己是否适应那边的生活,然后在做决定。
647
-
648
- **父母**: 我们两个人的服务年龄都在60岁上下,目前能照顾自己,虽然他们都不是很同意我们去那么远的地方去工作生活,但是也拗不过我们的决定,我有妹妹,我老婆有弟弟,他们也能在紧急的时候帮我们照顾他们。一方面在上海的时候,他们也帮我们照顾小朋友很多年了,也想给他们自己的时间,让他们有自己的生活,我爸就特别想把车练好,然后开车走一走中国.
649
-
650
- 所以整个决定就变成了:**让我们去阿姆斯特丹生活一段时间吧,小朋友去当地国际学校,妈妈不辞职,远程工作一段时间,爸爸原职位不变,只是换城市工作。**
651
-
652
- ## 流程
653
-
654
- 决定做好了之后,流程就比较简单了,和老板提出自己想去阿姆斯特丹工作的想法,然后老板和对应的老板沟通商议,然后确定新 Offer,HR 发新的合同,签订合同之后就开始 Relocation 的流程了,这部分公司有专门的 Global Mobility 团队来负责。所以只需要按照他们的步骤来一步步进行就好了。
655
-
656
- ### 签证申请
657
-
658
- 公司有专门的服务公司来帮忙完成这一部分,也就是向荷兰移民局(IND) 申请高技术移民签证和家庭成员的居留签证。这个过程还是需要一定的时间,当然对于我们来说,就是根据他们的材料清单去准备材料即可。如果一切都顺利,就收到到 IND 的 Approval Letter,上面有所有成员的 V Number, 有了这个之后,就可以预约荷兰大使馆或者领事馆去递签证了,使馆和领事馆递签也需要带必要的文件,递签顺利的换,几天之后就可以收到盖好签证的护照。有了护照就可以开始后面的流程了。
659
-
660
- ### 海运
661
-
662
- 公司有安排专门的搬家公司帮我们全程完成搬家,非常专业的搬家服务,他们会先和你预约一个时间进行初步的沟通,了解大致需要海运的东西,可能是为后期的海运打包工具,和打包人员安排做准备。然后预约一个现场打包的时间,当天他们会全部帮你进行打包和搬运上他们的车,你只需要告诉他们需要打包和搬运的物品即可,基本上不需要你动手。
663
-
664
- 基本上如果你想把整个家从上海复制到阿姆斯特丹几乎没有什么问题,只是我们一切从简,只海运那些我们需要的东西,比如一箱书籍,厨具,三辆自行车,衣物和棉被,刚买不久的床垫,以及不少的其他东西。
665
-
666
- ### 机票
667
-
668
- 基本只要拿到了签好的护照,就可以让公司帮忙预定机票了,我们的时间比较的紧凑,拿到护照之后只有不到十天的时候来进行海运的安排和飞机票的购买了,不过最后好在一切都很顺利,公司定的机票的日期前一天,海运正好弄完。如果没有让公司购买指定的航司,公司一般会优先预定KLM的航班。
669
-
670
- ## 出发
671
-
672
- 前一天刚刚打包完海运,今天一大早就出发去浦东机场了,所有的安排都是紧凑的,四个大大的箱子,四个些许有点忐忑又有点其他的心。而且姐姐努力上进的心,竟然说要在机场参加全国青少年信息素养大赛 Python 编程挑战赛的复赛。所以就有这张我办理登机牌时候,姐姐还在努力写程序的照片.
673
-
674
- ![coding](https://github.com/metrue/picx-images-hosting/raw/master/IMG_9735-2.2ven1apg7x.jpg)
675
-
676
- ### 飞行
677
-
678
- 我们乘坐的是 KLM 从上海浦东直飞阿姆斯特丹史基浦机场的航班,飞机基本满员,总共飞了13个小时50分钟,餐食还凑合,看看电影,玩玩游戏,睡睡觉,不知不觉也就到了。
679
-
680
- ### 落地
681
-
682
- 周六上海早上 11:30 出发,落地阿姆斯特丹的时间是下午的 19:05 分,跟着人群按照路标直接走到通关口即可,通关也很顺利,就简单问一下来阿姆斯特丹的目的,以及时间,看到我拿到的工作签证之后,盖个章便出来,去取行李。
683
-
684
- 公司有有安排好的出租车服务,取完行李按照公司提前发的路线图去等司机来接,看到小红书有不少朋友提到被出关开行李检查的经历,我们并没有发生,我也没有看到同飞机的任何人有被查,也许只是幸运。我们到了指定的候车点之后,直接打了司机的电话,天还很亮,上海三十几度的温度,到了阿姆斯特丹大约不到二十度,幸好我们都带来外套。几分钟之后司机就到了,司机很友善帮忙行李放到后备箱,很熟悉送到了公司安排的酒店。
685
-
686
- ### 酒店
687
-
688
- 公司为海外调到阿姆斯特丹工作的员工安排四周(单身)或者六周(家庭)的临时酒店,并且在酒店的接待处可以拿到一个小礼包,里面有一张公交卡, 这边是 OV Card, 和当地小零食,这个公交卡是为了在我们办理自己的各种卡之前方便出行用的。
689
-
690
- 我们的酒店位于 Cruiquiuseiland 的 YAYS Amsterdam Docklands, 入住之前短信和邮件都以及发送给我相关的入住信息,直接通过 pin code 就可以入住,一个两室的格局,可以做饭。当天到酒店时候,已经是晚上八点多了,所以洗漱结束之后就休息了。
691
-
692
- ## 第一周
693
-
694
- 这一整周天气都很好。这也是我选择七月来荷兰的原因,不想一开始进入 hard 模式。当然我这一周的主要任务有三个: 熟悉当地,BSN注册,居留证办理,银行卡办理。
695
-
696
- ### 第一天
697
-
698
- 因为正好是周六过来的,所以周日可以好好休息一天,调整一下时差。第二天早上,我们六点多就醒了,然后洗漱之后,就出门到附近走走,显然一大早除了运动的人,没有什么太多人,路上的人挺友善的打招呼,我们有点饿,不过基本上所有的店在 Google 地图上(还是 Yelp) 都显示尚未营业。在公交车车站,我们问一个老奶奶附近的超市在哪儿,是否已经开门,她英文挺好的,指路并且提到他们开门挺早,而且不远,她几乎每天都去。我们顺着她的方向走大约几百米,果然就到了。
699
-
700
- 超市和国内超市区别不大,不过大部分的商品信息多数是荷兰语。虽然很早,但是已经也有人采购东西,我们主要是购买一些面包,牛奶,蔬菜,和肉类,打算有空的时候做做饭,不了解的东西我都是直接用英文询问其他人,他们英文也挺好。
701
-
702
- 在我们回酒店的路途中,陆陆续续来来回回的人就多一些了,很多骑自行车的人,而路边也超多的自行车,不时就有人打招呼。
703
-
704
- ### 购物和交通
705
-
706
- 购物我基本上就直接去酒店附近的 Albert Heijin 或者 Jumbo,基本和国内的大超市也差多,生活用品基本上都可以买到,肉奶蛋类和国内价格似乎无差,蔬菜类会贵一些。如果你有一张 contactless 的 VISA 信用卡,大超市似乎应该都支持支付。不过我很失误,我只带了招商银行的mini信用卡,不支持 contactless, 基本上刷不了,幸好我带了一点欧元出来。
707
-
708
- 阿姆斯特丹的交通还是很便利的,有很多的选择: Train, Tram, Bus, Metro, Ferry, Bus, 当然最最最最最重要,还是 Bicycle 啦,自行车真的太重要了在这里,一方面是公共交通真的不便宜,另一方面,它真的应该是最方便的交通工具了。
709
-
710
- ### BSN 注册 和 IND 居留卡
711
-
712
- 公司的服务团队在我到阿姆斯特丹之前已经帮我预约好了 BSN 注册和 IND,所以我只需要按时间去到阿姆斯特丹外籍服务中心,现在叫IN Amsterdam。为了按时到达,我们早上吃饭早饭,就一起做上公交车,然后换乘电车到达了 IN Amsterdam。
713
-
714
- 因为我们家四个人都要办理,而且有小朋友,文件还是满多的,整个过程花了大约2个小时,办事人员也很友善,不过还是很顺利的,我们拿到了自己的 BSN 以及居留卡,从此就是合法阿姆斯特丹打工仔了。
715
-
716
- ![ind](https://github.com/metrue/picx-images-hosting/raw/master/IMG_2285.77dg8ua2cl.jpg)
717
-
718
- 在办理完 BSN 注册和居留卡之后我们在 IN Asterdam 的楼里吃午饭,没有想到,他们家还挺好吃,虽然略微有些贵,小朋友们很喜欢,我们吃的也很满意。
719
-
720
- ### 银行卡
721
-
722
- 公司把办理银行卡的时间约在 BSN 注册的下午,从 IN Amsterdam 到公司预约的银行 ABN AMRO 不是很远,公交车一会就到了,办理也很顺利,简单的信息了解,前几个字,就完成了我们两个人联合账户的初步开通,不过当场并不能拿到卡,需要审批完了之后后面直接邮寄到我的地址。
723
-
724
- ![bank](https://github.com/metrue/picx-images-hosting/raw/master/IMG_9856.1zi5luh8jg.jpg)
725
-
726
- ## 初印象
727
-
728
- 一周过去了,我也完成在阿姆斯特丹正常生活必备的一些步骤,新生活也慢慢展开了。阿姆斯特丹这一周给我的初印象大致是,
729
-
730
- ![company](https://github.com/metrue/picx-images-hosting/raw/master/IMG_2273.1sexqevuz1.jpg)
731
-
732
- 大家较为友好,也许是因为我接触的人还很少,但是整体来说,路上时不时都会有人友善的打招呼,遇到问题咨询的时候,大家也很耐心的解答。我们在路上掉了运动器材的包包,人们也很友善的提醒,我有一次在超市掉了二十欧纸币,也有人拿到外面找我归还;
733
-
734
- 英文的普及率很高,接触过的所有人都可以很流利的说英文,无论是公共部门的办事人员,还是路边的店员,或者是路人,无聊时上了年纪的老人,还是偶遇的年轻人,英文沟通都非常的顺畅。
735
-
736
- 城市比我想象中的漂亮,河道很多,建筑也很有特点,走在路上时不时都会有小惊喜,很可惜我们海运的三辆自行车还没有到,不然真的想好好骑行整个城市。]]></content>
737
- <published>2024-09-27T17:56:10.267Z</published>
738
- </entry>
739
- <entry>
740
- <title>华为鸿蒙 HarmaryOS Next 线下活动小记</title>
741
- <link href="https://blog.minghe.me/blog/%E5%8D%8E%E4%B8%BA%E9%B8%BF%E8%92%99-harmaryos-next-%E7%BA%BF%E4%B8%8B%E6%B4%BB%E5%8A%A8%E5%B0%8F%E8%AE%B0"/>
742
- <updated>2024-04-21T05:58:06.454Z</updated>
743
- <id>https://blog.minghe.me/blog/%E5%8D%8E%E4%B8%BA%E9%B8%BF%E8%92%99-harmaryos-next-%E7%BA%BF%E4%B8%8B%E6%B4%BB%E5%8A%A8%E5%B0%8F%E8%AE%B0</id>
744
- <content type="html"><![CDATA[---
745
- title: 华为鸿蒙 HarmaryOS Next 线下活动小记
746
- date: 2024-04-21T05:58:06.454Z
747
- ---
748
-
749
-
750
- ![54A32E3D-418E-496C-BAC8-1DC951BB8764_1_102_o](https://github.com/metrue/picx-images-hosting/raw/master/54A32E3D-418E-496C-BAC8-1DC951BB8764_1_102_o.2h83p85e3m.webp)
751
-
752
- ## 偶然决定
753
-
754
- 很久都没有参加线下活动了,周末的时间基本上,要么陪小朋友运动,要么陪小朋友写作业或者准备比赛,要么陪夫人练车。很偶然的在朋友圈刷到华为鸿蒙的线下开发者活动,心血来潮就报名了,捡一捡线下开发的感觉,也是一个很好的了解鸿蒙生态的一个机会吧。
755
-
756
- ![Screenshot-2024-04-22-at-10](https://github.com/metrue/picx-images-hosting/raw/master/Screenshot-2024-04-22-at-10.07.27.7awyld9bmx.webp)
757
-
758
- 我甚至都没有详细看活动议程,甚至都没有想过是不是需要做一点准备,而本人也确实没有一点鸿蒙开发的经验,甚至 Android 开发也没有正经弄过,也就是维护两个小 iOS 应用。但是不妨碍我参加一个以鸿蒙为主题的开发者比赛活动呀,没准比赛中可以完成一个最小可用产品,顺利的开启自己的鸿蒙生涯呢。
759
-
760
- ## 活动当天
761
-
762
- ### 早上
763
- 周日和夫人安排好小朋友的学习和活动安排,提醒夫人关注好小朋友的事项安排重点之后,我就出发去活动了,原来活动在徐汇漕河泾的字节办公楼,我从杨浦江湾体育场这边过去,相当于从上海的北边到南边,还是蛮远。想到地铁还要转车,算了咖啡直接打车吧。
764
-
765
- 上了车想到如果要组队,要不就随机叫个朋友一起吧,所以发个消息给 @Chester ,Checster 也很干脆,一起来玩了。等我到场地时候,活动已经开始了,迟到了十几分钟。Chester 比我迟到更多了,我们完全没有注意到活动的议程,其实人家的流程还是紧凑的。
766
-
767
- ![5FAF4CFC-0DE3-4D44-A10A-44B03A134F3C_1_102_o](https://github.com/metrue/picx-images-hosting/raw/master/5FAF4CFC-0DE3-4D44-A10A-44B03A134F3C_1_102_o.1seu57ih4r.webp)
768
-
769
- 早上主要主办方和华为工作人员对活动和鸿蒙的一些介绍,我们两人在期间对于今天要做什么进行一些头脑风暴,"Cross OS HandOff" 这个想法很自然的就到我的脑海中,简单的讨论之后我们就决定做这个想法了。跨生态互操作,想想就很好玩,当然也想想就好难,不过我想着做一个PoC应该问题不大。
770
-
771
- ### 午餐
772
-
773
- 大约到了十二点多开始午餐,午餐很一般,略过.
774
-
775
- ### 下午
776
-
777
- #### 设计
778
-
779
- 下午就是写代码的时间啦. 我们基本上采用了 "Demo Driven" 的开发方案。首先当然是定义我们的目标了。
780
-
781
- **我的愿景: 移动设备用户在不同生态(iOS, Android, HarmonyOS等)的设备之间可以做到无缝的持续性操作.**
782
-
783
- *场景1*: 比如我在的的 iPhone 手机上的记事本上正在创作,突然想要切换我的 HarmonyOS 笔记本上继续我的创作,键盘输入让我创作更快捷。这时候如果有了 Cross OS 的 HandOff, 它将自动把我 iPhone 上的记事本的状态变成 HarmonyOS 上记事本的应用状态,我直接在 HarmonyOS无缝的继续我的创作。
784
-
785
- *场景2*: 比如我在的 HarmonyOS 的笔记本上上的地图软件上查询我到目的地路线,现在我准备出门打车,那么我就可以通过 Cross OS HandOff 的功能在我的 iOS iPhone 手机上的地图应用继续的操作。
786
-
787
- 这些都是我最初想法想达到的愿景,但是想到现在也就是不到两个小时的时间了,我们如何实现一个 demo 来阐述我们的理念呢。其实要达到我们的目标,主要完成两个主要的部分:
788
-
789
- > 为了更好的表达,我们把两个不同的生态上的应用分别进行简单的编号. 在运行着 iOS 系统的 iPhone 设备的某应用程序,我们编号 A. 在运行着 HarmonyOS 系统的鸿蒙设备的某同类型的应用程序,我们编号 B.
790
-
791
- * 应用状态快照
792
-
793
- 为了实现 A 到 B 的 HandOff, 我们需要先将此刻的 A 的状态进行快照。
794
-
795
- * 数据传输
796
-
797
- 为了实现在 B 上继续用户在 A 上的操作,我们需要将上一步的 A 的应用程序状态快照传输到 B 的设备上。
798
-
799
- * 应用状态恢复
800
-
801
- 当运行在 B 的设备收到 A 的状态快照之后,将状态快照恢复成 B 可以识别的状态,并且应用到 B 应用上。
802
-
803
- 但是很显然,在两个小时里我们是无法完成一个完善的方案的,所以我们最后定下来一个方案实现 PoC 并且很大概率可以完成现场 demo 的方案。
804
-
805
- > 两个设备通过局域网进行通信,然后可以选择一个 Mac 应用,在Mac 进行一些一系列操作之后,然后我们转移到 HarmonyOS 设备上时,我们可以在同一个应用(或者同类型)的应用继续我们之前在 Mac 上的工作,保持完整的持续性.
806
-
807
- 这样我们就很完整的展示我们的概念,**然而**现实环境还是残酷,[^7b0daa3b-0af8-450f-824d-52aea73be8f7-1714018784523]在现场华为工程师的协助下,我们仍然没有办法成功在我们的 Mac 上能够完成 DevEcho - Studio 上运行一个 HarmonyOS 的模拟器,所以为了在短暂时间内有一个像样的 demo,我们选择一个简单的场景:
808
-
809
- > 我在我的 Mac 上运行一个剪贴板管理 uPaste,我的队友也在他的 Mac 上运行这个 uPaste, 然后我会在我的 Mac 上进行一系列的复制粘贴操作,在不依赖 Mac 系统的内置同步功能的情况下,这些操作会自动在另外一台 Mac 的 uPaste 应用上自动同步.
810
-
811
- #### 实现
812
-
813
- * 数据传输
814
-
815
- 我们俩对于网络部分的知识确实有些捉襟见肘,想着无论是基于蓝牙,还是 WiFi 都可以,至少不能直接使用公网来传输数据。简单搜索一通之后,我们感觉无论是使用 WiFi Direct 还是蓝牙,感觉我们都无法这两个小时内 demo 出完整的流程,所以我们决定:直接在同一个局域网内,两个设备通过 Socket 来进行数据通信.
816
-
817
- * 应用数据状态发送
818
-
819
- 因为我们选择了最简单的剪贴板管理应用,所以应用状态就就很简单了: 用户当前的剪贴板内容. 所以我们只需要在适当的时候(用户进行 HandOff 操作的时候)进行一个剪贴板内容发送即可.
820
-
821
- * 应用数据状态恢复
822
-
823
- 而在目标设备上,我们只需要将接收到剪贴板数据,写入到当前设备的剪贴板即可。
824
-
825
- 这样这个演示的流程就简单可控了,在清楚阐述我们的设计思路的同时也确保最低概率的演示翻车.
826
-
827
- 所以整个演示就变成了几段非常简单的代码而已。
828
-
829
- 监听并且收到数据之后直接写入剪贴板.
830
-
831
- ```py
832
- import socket
833
-
834
- class Server:
835
- def __init__(self, host, port):
836
- self.host = host
837
- self.port = port
838
- self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
839
-
840
- def start(self):
841
- self.server_socket.bind((self.host, self.port))
842
- self.server_socket.listen()
843
- while True:
844
- client_socket, client_address = self.server_socket.accept()
845
- self.handle_client(client_socket)
846
-
847
- def handle_client(self, client_socket):
848
- while True:
849
- data = client_socket.recv(1024).decode()
850
- if not data:
851
- break
852
- client_socket.close()
853
-
854
- if __name__ == "__main__":
855
- HOST = '172.20.10.15' # Listen on all available interfaces
856
- PORT = 8080
857
- server = Server(HOST, PORT)
858
- server.start()
859
-
860
- ```
861
-
862
- 持续从剪贴板读取数据,如果有变化通过 socket 发送剪贴板内容。
863
-
864
- ```py
865
- import socket
866
- import subprocess
867
-
868
- def get_clipboard_content():
869
- process = subprocess.Popen(['pbpaste'], stdout=subprocess.PIPE)
870
- output, _ = process.communicate()
871
- return output.decode('utf-8')
872
-
873
- class Client:
874
- def __init__(self, host, port):
875
- self.host = host
876
- self.port = port
877
- self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
878
-
879
- def send_message(self, message):
880
- self.client_socket.connect((self.host, self.port))
881
- self.client_socket.sendall(message.encode())
882
- self.client_socket.close()
883
-
884
- if __name__ == "__main__":
885
- HOST = '172.20.10.5' # IP address of the receiver
886
- PORT = 8080
887
-
888
- tmp = get_clipboard_content()
889
- while True:
890
- source = get_clipboard_content()
891
- if source and source != tmp:
892
- client = Client(HOST, PORT)
893
- client.send_message(source)
894
- tmp = source
895
-
896
- ```
897
-
898
- 上面的代码就是当时我们 demo 所使用的代码,你可能会发现非常多的改进点,但是这就是 demo,让流程走起来比代码的完善更重要,一切的改动的出发点应该都是让 demo 更加完整流畅,能让观众和评审更容易理解和参与。
899
-
900
-
901
- #### Demo
902
-
903
- 可能是周末写字楼物业不开空调还是怎么的,活动的会议室非常的热,我们只能跑到外面的开放空间写代码。我们一个个的解决掉项目中的问题,感觉似乎从演示的层面上差不多的时候,工作人员跑过来说“你们怎么还在这呢,演示都开始了”,后来我们才了解到,原来最终的作品其实不需要一个可以运行的代码,只要一份演示的 ppt 即可,并且演示是需要报名的,只有十个名额,显然像我们这样,人家都开始演示,我们都还在调试代码的团队,显然就没有机会了。
904
-
905
- 然而在我们回到会议室,看着别人的演示,觉得既没有特别惊艳的创意,也没有硬核的技术展示的时候,我们琢磨着全部参加完整个流程似乎太晚回家了,打算伺机离开的时候,评委说:“我们再增加两个展示名额吧”,看来评委也希望可以看到更多的项目,更多的可能性。我们想着既然做都做了,展示成果,也算今天没有白来。所以立即就举手上台展示了.
906
-
907
- 玩完没有想到,展示的效果还挺好,现场观众的反应和评委的评价都比较的积极,还是蛮开心。
908
-
909
- > 小插曲: 不知道为啥,当我们使用场地的局域网的时候,socket 连接不成功,最后我们只能通过我们手机开热点形式来完成我们的展示.
910
-
911
- ![9B1AFD7E-A216-4C74-A89F-1C24FBE0064F_1_102_o](https://github.com/metrue/picx-images-hosting/raw/master/9B1AFD7E-A216-4C74-A89F-1C24FBE0064F_1_102_o.45h80rrfe.webp)
912
-
913
- #### 投票和获奖
914
-
915
- 万万没想想到,最后我们获得票数第二名的成绩,当然这也包括我们自己的投票😂,但是很开心,希望我们在后面的六月份的决赛中[^aC5taW5naGVAZ21haWwuY29t-1721555382700],也可以也能收获幸运。
916
-
917
- ![CC35F46A-C5B7-4F35-96E5-7D27B6E52B44_1_102_o](https://github.com/metrue/picx-images-hosting/raw/master/CC35F46A-C5B7-4F35-96E5-7D27B6E52B44_1_102_o.60u1f17vuf.webp)
918
-
919
-
920
-
921
- [^7b0daa3b-0af8-450f-824d-52aea73be8f7-1714018784523]: 华为如果可以在开发者体验方面再进一步,将极大有助于生态的繁荣.
922
-
923
- [^aC5taW5naGVAZ21haWwuY29t-1721555382700]: 很可惜,由于客观原因,我们没有能前往东莞参加决赛.
924
- ]]></content>
925
- <published>2024-04-21T05:58:06.454Z</published>
926
- </entry>
927
- <entry>
928
- <title>远程工作者的一天</title>
929
- <link href="https://blog.minghe.me/blog/a-day-of-remote-worker"/>
930
- <updated>2019-06-09T16:30:26.223Z</updated>
931
- <id>https://blog.minghe.me/blog/a-day-of-remote-worker</id>
932
- <content type="html"><![CDATA[---
933
- title: 远程工作者的一天
934
- date: 2019-06-09T16:30:26.223Z
935
- external_discussions:
936
- - platform: v2ex
937
- url: https://v2ex.com/t/572394
938
- ---
939
-
940
-
941
- ![remote-work.jpg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-03-22/1742652676821.jpg?raw=true)
942
-
943
- 很多人喜欢远程工作, 也有很多人多反对远程工作, 远程工作意味着:
944
-
945
- ## 雇主
946
-
947
- * **只能以员工的产出来衡量员工的价值**
948
-
949
- 雇主雇佣员工的目的是需要这个人的产出,但很多时候很奇怪,很多雇主却花心思去关注这个个员工是不是呆在办公室8个小时,是不是愿意加班.
950
-
951
- * **提供对异步工作模式友好的基础设施**
952
-
953
- 相比于传统的办公模式,远程工作对公司办公室的硬件条件要求较低,不需要奢华的办公楼,但是需要一些必备的工具来进行高效的异步沟通. 比如 Slack, Zoom, GitHub, JIRA, Google Document 这些沟通,协作,文档工具工具,也需要 VPN 这样的网络工具, 同样 CICD 的工具链也是必不可少,但是这已经是任何技术公司的必备了。
954
-
955
- * 招聘合适的人
956
-
957
- 对于支持远程工作的企业来说,人才库就从一个城市变成了全世界了,因为你不需要候选人来办公室坐班,所以只要条件满足,全世界的人才原则上你都可以挖掘,当然和所有的招聘一样,风险是存在的,所以 "Hire Slow, Fire Fast" 原则仍然适用,不是每一个人都能适应一个没有同事在身边的工作,有的人是难以自我管理,有的人更喜欢同步工作,有的人不能忍受"孤独"等等。所以招聘一个合适的人变得更难。
958
-
959
- ## 员工
960
-
961
- * **只能用高效的产出来证明自己的价值**
962
-
963
- 你不再有任何的借口让自己偷懒,因为你的节奏你都已经全权控制,你不能在怪环境,怪时间,你必须成熟的学会管理你的自己时间和精力,管理StateHolders 的期望。
964
-
965
- * **选择自己最高效的时间和环境来工作**
966
-
967
- 你不需要再去忍受办公室有的同事那些肆无忌惮的噪声(打电话,机械键盘, 或者公共区域的聊天), 你也不用去忍受总有一些必须的会议被安排插入到你的代码时间里面,更不会有人突然就冲到你的工位对你的屏幕指手画脚.
968
-
969
- 你可以选择你喜欢的咖啡店,书店,公园,海边,甚至喜欢的城市或者国家. 你也可以选择低迷的时间去运动,然后在高效的时间工作.
970
-
971
- * **更便利的肩负照顾家庭的责任**
972
-
973
- 你几乎不会在错过女儿的第一次上台表演,接到幼儿园儿子不舒服的电话,你也可以第一时间去带他去就医,和父母吃晚饭,聊聊家常。你终于除了给他们经济的帮助之外也给予他们陪伴。
974
-
975
- * **有成块的时间培养自己**
976
-
977
- 省去了在京沪上下班的漫长拥挤的地铁,没有任意插入的会议,没有随意被打扰的办公室环境, 你有了成块(1小时以上)去发展自己,也许是开源项目,也许是系统的学习新知识,也许是艺术和音乐的爱好,利用这样的时间块,你会成为一个更好的自己,你会少了很多的抱怨,多和很多的努力。
978
-
979
- ## 我的典型一天
980
-
981
- 虽然以前所在公司都曾经不同程度的 WFH (Work from Home), 但是真正加入一个纯 remote 的团队还是第一次, 是一种全新的尝试和挑战, 我也在不断的学习和适应当中,不知不觉两周过去了, 算下来每天的 Coding 时间大约在 2h - 3h 之间,PR Review 和 Design Review 大约在 1h 以内,和同事的会议平均每天 25min 左右,有较为成块的时间来进行系统学习和实验,也终于有了较多的时间给自己的儿子和女儿。
982
-
983
- 附上我的一个粗略的时间表.
984
-
985
- **上午**
986
-
987
- * 07:40 - 08:00 早上起床,完成洗簌.
988
- * 08:00 - 08:40 带女儿出去吃早餐,然后送女儿去幼儿园.
989
- * 08:40 - 09:00 去家门口咖啡店, 或者远一点的店找一个不错的位置,然后点一杯拿铁或者美式.
990
- * 09:00 - 09:30 查看和回复 Slack 和邮件, 然后看一下今天的任务优先级,开始进入工作状态.
991
- * 09:30 - 11:00 写代码 --> 写测试 --> Pull Request. 或者 Review Pull Request, Review Architecture Design.
992
- * 11:00 - 11:30 和同事的会议一般都尽可能的安排在这个时间.
993
- * 11:30 - 11:45 刷一下 GitHub Explore, HackerNews, 和 Reddit 的相关 Channels, 顺便 Twitter, 微博,v站划划水.
994
-
995
- **中午**
996
-
997
- * 11:45 - 12:30 如果在家门口的咖啡店就会回家和儿子父母吃午饭, 远的话就直接在店里解决午饭的问题.
998
- * 12:30 - 13:20, 和儿子去球场运动或者在家里玩玩具,儿子作息和规律,玩一会他就会开始午睡.
999
- * 13:20 - 13:30 回到咖啡店,一杯冰拿铁.
1000
-
1001
- **下午**
1002
-
1003
- * 13:30 - 14:00 写一道算法题, 偶尔会在 typing.io 上进行输入练习.这是工作日的 kata.
1004
- * 14:00 - 15:30 密集的代码编写,测试,重构的时间,然后发 Pull Request, 更新相关的文档.
1005
- * 15:30 - 16:20 去幼儿园接女儿,然后带她吃点东西,送回家,
1006
- * 16:30 - 17:30 在家工作, 主要是 Review 同事的PR Review 和 对自己的PR 进行必要的重构,最后在 Slack 总结发出当日状态的明天的安排.
1007
- * 17:30 - 18:40 送女儿去课外兴趣班,一般也会带着电脑和正在看的书. 偶尔也会进行 PR Review 或者看书.然后发现 iPad + 便携式的键盘非常适合在非工作场所写东西.
1008
-
1009
- **晚上**
1010
-
1011
- * 19:00 - 22:00 回家吃晚饭,给小宝贝们洗澡,和媳妇带他们在小区或者旁边的商场散步,或者在家陪他们玩电子设备或者数学游戏,然后讲故事带他们睡觉.
1012
- * 22:30 - 24:00 看 Slack 和邮件,回复紧急信息,然后写文字或者代码.
1013
- * 24:00 上床睡觉,时常带着耳机看美剧或者武林外传,听着听着就睡着了.]]></content>
1014
- <published>2019-06-09T16:30:26.223Z</published>
1015
- </entry>
1016
- <entry>
1017
- <title>如何衡量一个团队是否值得加入</title>
1018
- <link href="https://blog.minghe.me/blog/work-going-index"/>
1019
- <updated>2019-05-21T09:43:38.234Z</updated>
1020
- <id>https://blog.minghe.me/blog/work-going-index</id>
1021
- <content type="html"><![CDATA[---
1022
- title: 如何衡量一个团队是否值得加入
1023
- date: 2019-05-21T09:43:38.234Z
1024
- ---
1025
-
1026
- 最近有人在 [Hacker News](https://news.ycombinator.com) 问 ["How do I find a meaningful software engineering job?"](https://news.ycombinator.com/item?id=17332796), 其中有一个人的回复我觉得有点意思, 而且和现在的看法有些些许的类似。
1027
-
1028
- > I'm a late-career software developer. 30+ years in the trenches doing this...
1029
- > I've done "meaningful" work at companies that treated my like a consumable resource, and less meaningful work at companies that treated me like a person. I prefer the latter. My suggestion is don't jump at the first interesting work, look more for culture and career opportunity. You can find both, those jobs are not quite as rare as unicorns.
1030
-
1031
- 最近和常常和 [Jakehao](https://twitter.com/haojianzong) 聊聊工作这个事,什么样子的工作才是好工作,我们不断的跳槽到底在挑什么. 我和 Jake 经过这几年的工作经历,都觉得自己并没有单单为了工资而跳槽,由于我们俩都有过不成功的换工作经历,在一个自己不喜欢的地方和氛围下工作,是一种极其折磨人的状态,一般很难呆太久。在找工作的时候,我们两不时会聊自己的面试情况,自己的心态和感受,经过简单的总结之后,我们得到了这样一个公式
1032
-
1033
- ```
1034
- WGI = WLB * PV * SL * TA
1035
- ```
1036
-
1037
- > WGI ( Worth Going Index): 值得去指数
1038
- > WLB (Work Life Balance): 工作生活平衡
1039
- > PV ( Product Value ): 产品价值
1040
- > SL ( Salary Level ): 工资水平
1041
- > TA ( Team Atmosphere ): 团队氛围
1042
- WGI 越高,这个工作机会的价值越高,越值得我们去尝试;反之,WGI 越低则越表明这个工作机会的价值越低,越不值得我们尝试。
1043
-
1044
- WGI 的这四个决定因素: 工作生活平衡 ( Work Life Balance, WLB), 产品价值( Product Value, PV ), 工资水平 ( Salary Level, SL), 和团队氛围 ( Team Atmosphere, TA ). 是来源我们两个数次的成功或者失败的换工作经历的总结而来的。
1045
-
1046
- ## Work Life Balance
1047
- 工作生活平衡,966 在很多中国的 IT 公司不知不觉已经常态,这有点让人泄气,对很多人来说,也包含着有些无奈。 我是旗帜鲜明的排斥任何形式的加班的,我不喜欢任何形式的 Push。每一个人都是成年人,成年人就应该知道怎么规划自己的时间,怎么安排自己的工作,怎么去做任务的优先级排序,尽量少的给别人造成障碍和拖累拖累团队。绝大多数的加班都是无意义的,作为 Leader/Boss 让你的团队成员加班,就是赤裸裸用战术的勤奋来掩盖战略的愚蠢,无可争辩。
1048
-
1049
- ## Product Value
1050
- 由于工作占据了我们生活的很大一部分,把自己那么大的时间和精力投入到一个没有太多意义的产品研发中,很难保持长久的激情。 如果参与到一个对自己,对这个社会有意义的产品开发中,每一次的代码的提交,都在让这个世界变得更好一点点,让人们的生活变得更好一点点,会让我们能保持一种充满激情的工作状态,而这种状态也让我们做事情事半功倍,每天的工作都是一种享受,也有助于我们有更多的时间去享受工作之外的生活。
1051
-
1052
- ## Salary Level
1053
- 工资水平,我们都是平凡人,都需要买面包和牛奶。我们不是神,所以不能靠各种画出来的大饼来填饱肚子。
1054
-
1055
- ## Team Atmosphere
1056
- 团队氛围,好的团队让每一个人都工作开心,相处融洽,相互帮助,分享知识,共同成长。好的团队并不是说要每一个人都要成为好朋友,我们都有自己的私人空间,尊重是一个好的团队的前提,尊重个人自由,尊重个人选择,尊重个人独立的想法。互助合作,每一个人都有新手时期,作为一个资深者应该给新人适当的给予帮助。团队中齐心协力才能让团队获得成功,但是团队成功并不意味着必须牺牲个人成功,相反,团队关心以及帮助团队成员获得个人的成功会更加有助于团队的成功。
1057
-
1058
- 有了这个公式之后,在我们找工作做选择有一个清晰的对比了,我把自己经历过的工作粗略的挨个计算了一下,结果如下:
1059
-
1060
- ```
1061
- Company WLB PV SL TA WGI
1062
- Synopsys 1 0.7 0.7 0.7 0.343
1063
- Second Spectrum 0.8 0.6 0.8 0.8 0.3072
1064
- Splunk 1 0.6 0.9 0.9 0.486
1065
- 设计家 0.5 0.7 0.8 0.8 0.224
1066
- Udacity 1 0.9 0.8 0.9 0.648
1067
- ```
1068
-
1069
- 不妨你也是计算一下你的前任和现任雇主们吧.
1070
- ]]></content>
1071
- <published>2019-05-21T09:43:38.234Z</published>
1072
- </entry>
1073
- <entry>
1074
- <title>2017 年终总结</title>
1075
- <link href="https://blog.minghe.me/blog/2017-summary"/>
1076
- <updated>2017-12-30T09:20:02.233Z</updated>
1077
- <id>https://blog.minghe.me/blog/2017-summary</id>
1078
- <content type="html"><![CDATA[---
1079
- title: 2017 年终总结
1080
- date: 2017-12-30T09:20:02.233Z
1081
- ---
1082
-
1083
- 2017 是很忙碌的一年,离开很自由的 Splunk,来到了现在的 [设计家](https://www.homestyler.com/)团队,换了团队,换了行业,也换工作方式,很多地方需要适应,不管怎样,每一个新的开始都是一个挑战。所以我还是怀着愉快的心情来写这篇年终总结吧.
1084
-
1085
- ### 工作
1086
- 也许全屋定制团队是整个居然设计家上海最忙碌的 Scrum Team 吧,查看打卡就知道我们的成员有多少次都是工作到最晚的。虽然没有强制性的 996, 但是平均下来我们相对 996 过犹不及。
1087
-
1088
- * 重构 3D 工具
1089
-
1090
- 3D 工具作为一个拥有复杂功能,而且历史长久的项目,它拥有这超过 25w 的 JavaScript 代码,无数的 CSS 文件,无数的各类资源文件。而且各种管理风格千差万别。 JavaScript 部分: 既有基于 Google Closure 构建方式的代码,又有 jQuery 风格的大量操作 DOM 的代码,还有很多 ES3/ES5 的代码,还有今年来才引入的 ES6/ES7 风格的代码,还有无穷的原生的 JavaScript 代码。而在 CSS 方面,有原生 CSS 写法,也有 Less/Saas。
1091
- 而在代码架构方面,3D Tools 实际的架构是这样的:
1092
- ```
1093
- App = App Core + Plugins
1094
-
1095
- App Core = (App Transaction Management) + App Data Model + App Views
1096
- ```
1097
- 为了更好支撑未来更复杂的需求,更快的开发效率,我们对这个代码库进行调整,细节可以在我的这篇文章 [记一次大规模重构](https://blog.minghe.me/a-complex-web-app-refactor/) 了解到,当时真是初生牛犊不怕虎啊,刚到公司不到一个月,才敢对多年历史的复杂项目大刀阔斧的改造。虽然期间又一些问题,不过对于我个人而言,这样的经验无疑是珍贵的,在很短的时间就了解到整个产品的各方各面,对于我如今的开发都是非常有帮助的。
1098
-
1099
- * 橱柜定制从 3D 工具应用独立出来
1100
-
1101
- 橱柜定制作为整个全屋定制项目的排头兵,为了适应以后的快速迭代,我们把橱柜定制从原来作为 3D 工具的一个 plugin 独立出来成为了一个独立的应用,独立的 CodeBase, 独立的 CI/CD。 这个过程充满的艰辛和刺激,估计只有我和 Jerry 知道吧。 从以前作为一个依赖于 3D 工具的 plugin, 如何能够以最小的依赖,而且非功能退化的独立出来成为一个专用应用,这是不小的挑战,但是我们做到了。
1102
-
1103
- * 我们从 0 开始搭建整个 3D 定制的参数化引擎
1104
-
1105
- 任何的引擎都可以这么表征
1106
- ```
1107
- engine = f(input, rules)
1108
- ```
1109
- 不同使用场景 (Domains) 的引擎会有不同的引擎规则 (Rules),而对于家装设计领域,我们的 Rules 来源是各个家装设计公司和生产厂商。如果在这个特殊的领域需求里面抽象出更加适合工程实现的引擎模式成为我们的最头痛的事情,好在团队中的老司机在 Autodesk 已经塌坑无数,在短短的两个月时间里,我们做好了整个参数化引擎,并且在橱柜定制 App 中成功使用,为即将开始的全屋定制打下坚实的基础。
1110
-
1111
- * 内部 Hackathon 二等奖
1112
-
1113
- 到了[设计家团队](https://shejijia.com)之后就一直想在公司内部搞一场 Hackathon,所以当同事和我说他也想搞的时候,我们就一拍即合,和公司申请了经费,而且老板也支持。虽然其中有一些意外,但是整体还是成功的,而且老板也把 Hackathon 变成了每年两次的常规活动。更值得一提的是我们团队的作品: 小居 - 家装设计语音助理, 也很荣幸的获得二等奖,很是意外。语音交互也许是未来的一个很重要的交互入口,所以一早就有给我们公司的产品条件语音交互功能的想法,所以索性就在这次 Hackathon 实践一下,所以离我哪行中想要达到的样子还差的很远,但是基本的流程已经成型,而且玩了简单的交互。也算是一次成功的尝试吧。
1114
-
1115
- ### 开源项目
1116
-
1117
-
1118
- * [fx](https://github.com/metrue/fx)
1119
-
1120
- 在 [GoHack2017黑客马拉松](http://gohack2017.golangfoundation.org/) 虽然没有获奖,但是在那场比赛中完成的 [fx](https://github/com/metrue/fx) 成为我去年的小小高光时刻: 在 [Show HN: Fx - Poor man's serverless framework](https://news.ycombinator.com/item?id=15686661)发布了之后,迅速串升到Github Go Trend 榜单的第一名,并且持续在榜单首页超过一个星期,Stars 数目如今也吵过 1k, 当然更值得纪念的是,我和 [@TJ](https://github.com/tj) 大神终于有同框了,哈哈。
1121
-
1122
-
1123
- * [YoYo](https://github.com/metrue/YoYo)
1124
-
1125
- 而 YoYo 则是一个自己的一个需求:想要一个很干净纯洁的博客留言系统,不要有各种乱七八糟的社交按钮或者广告,所以我就着手自己写一个系统,留下 email 和你想说的话就可以留言,一个纯 JavaScript 的项目,可以在这篇文章[2017-04-18-YoYo:自己打造一个评论服务](https://minghe.me/2017-04-18-YoYo:%E8%87%AA%E5%B7%B1%E6%89%93%E9%80%A0%E4%B8%80%E4%B8%AA%E8%AF%84%E8%AE%BA%E6%9C%8D%E5%8A%A1.html)详细了解。
1126
-
1127
- * [Singular.Fm](https://singular.fm/)
1128
-
1129
- 是的,我参与的 podcast 终于上线了,很早之前就想要做一档 podcast, 但是一直没有狠下心来实施,后来和 [@梯田](https://weibo.com/titantse?refer_flag=1005050005_) 闲聊,正好他也有兴趣,所以一拍即合,说干就干,我们在年前终于录制了一期。希望可以持续做下去。
1130
-
1131
- * [MindPalace](https://mpapp.tk/)
1132
-
1133
- [@Jakehao](https://twitter.com/haojianzong?lang=en) 从深圳来上海玩,下飞机之后突然说有一个idea,稀里哗啦的和我说一通,我没有听太明白,索性就花了一张图给我看,然后我明白了,这就是一个关于人的日志记录工具啊,Splunk 是记录机器日志的,要是有一个app可以让记录人的日志(心思)变得容易,而且随时可以检索,那么一定棒极了,所以当即就决定和他一起做这个app. 然后我们两个都好忙,发布了第一个 Test Flight 了之后,我们还没有太多的时间的高强度的继续开发。只能周末的时候一起搞搞。
1134
-
1135
- ### 后记
1136
- 做工程师最好玩的地方在于,我们随心所欲的创造,一台电脑,一杯咖啡,一个好玩的创意,就可以让我们在一个地方默默的写几天代码,因为这就是我们的世界,简单而自由的世界。
1137
- ]]></content>
1138
- <published>2017-12-30T09:20:02.233Z</published>
1139
- </entry>
1140
- <entry>
1141
- <title>用 Golang 写一个支持各种编程语言的 serverless 框架</title>
1142
- <link href="https://blog.minghe.me/blog/first-golang-project-fx"/>
1143
- <updated>2017-10-22T17:42:13.233Z</updated>
1144
- <id>https://blog.minghe.me/blog/first-golang-project-fx</id>
1145
- <content type="html"><![CDATA[---
1146
- title: 用 Golang 写一个支持各种编程语言的 serverless 框架
1147
- date: 2017-10-22T17:42:13.233Z
1148
- external_discussions:
1149
- - platform: hackernews
1150
- url: https://news.ycombinator.com/item?id=15686661
1151
- - platform: v2ex
1152
- url: https://v2ex.com/t/406259
1153
- - platform: reddit
1154
- url: https://www.reddit.com/r/programming/comments/7su688/fx_is_a_homemade_faas_tool_like_aws_lambda/
1155
- ---
1156
-
1157
-
1158
-
1159
-
1160
-
1161
- ## 前言
1162
-
1163
- fx 是我在 [Go Hack](http://gohack2017.golangfoundation.org/)的一个小作品,Go Hack 是一个以Go语言为主要编程语言的黑客马拉松比赛。虽然我和我队友两人都是写JavaScript的前端工程师, 以Golang 零基础参加这次比赛,不过很开心我们完成了fx,也喜欢上 Golang 这门语言.
1164
-
1165
- 读了那么多年书,写了那么久的代码,如果说有什么概念是深入骨髓的,只能说是”函数“了。虽然在数学上和编程上,“函数”这个词有很大的不一样的,但是有一点上它们是类似:
1166
-
1167
- ```
1168
- 接受输入(可能为空值),然后进行处理,最后输出处理结果。
1169
- ```
1170
-
1171
- 我们几乎可以用这个概念来描述所有的行为. 比如我们可以用下面的函数的来描述我们 fx 的诞生过程:
1172
-
1173
- ```
1174
- 函数 f = Go Hack (以 Golang 为项目编程语言的黑客马拉松活动)
1175
- 输入 input = [两个Go语言零基础的JavaScript工程师,两台Macbook,很多很多的功能饮料]
1176
- fx = f(input)
1177
- ```
1178
-
1179
- ## fx 是什么
1180
-
1181
- 那么 fx 是什么呢,一句话来说就是 : fx 是一个可以把一个函数变成一个服务的工具. 一个简单的例子来说一下 fx 的功能吧. 比如你写好了很棒的函数 , 它是这样的:
1182
-
1183
- func.js
1184
- ```javascript
1185
- module.exports = (input) => {
1186
- return parseInt(input.a, 10) + parseInt(input.b, 10)
1187
- }
1188
- ```
1189
-
1190
- 它的作用就是计算两个数的和. 你把这个函数写在 `func.js` 这个文件里面。 这时候你希望可以将这个函数编程一个服务,对外提供一个 url 可以供外界访问. 但是想到 nginx, web server, api gateway…, 你头有点大了。 现在你可以简单的这样做。
1191
-
1192
- ```shell
1193
- fx up func.js
1194
- ```
1195
-
1196
- 如果一切没有什么问题,你可以得到一个url.
1197
-
1198
- ```shell
1199
- $ fx list
1200
-
1201
- +------------+---------+---------------+
1202
- | ID | STATE | URL |
1203
- +------------+---------+---------------+
1204
- | ce925443d5 | running | 0.0.0.0:40549 |
1205
- +------------+---------+---------------+
1206
- ```
1207
-
1208
- 访问你的服务试试看
1209
-
1210
- ```shell
1211
- $ curl -X POST 0.0.0.0:40549 -H "Content-Type: application/json" -d '{"a": 1, "b": 1}'
1212
- ```
1213
-
1214
- 你会得到 `2`. 这说明你的函数已经变成了一个服务了。
1215
-
1216
- ## fx 如何工作
1217
-
1218
- fx 有两个部分组成,fx server 和 fx client, 最开始的 client 和 server 基于 websocket 进行通信,所有的交互基于 websocket message 来进行, 当时选择 websocket 的原因是因为其简单,能够快速验证我们的想法。当项目做完了演示了之后放到了 [Github](https://github.com/metrue/fx) 之后, 收到了很多的反馈,有同学提出了可以采用 RPC 架构来做,gRPC 如雷贯耳很长时间,就是没有机会去实践,但是后来工作一直很忙,所以没有能够及时完成迁移,然后社区的力量是强大的,一个就职于意大利FBK的哥们发Email和我说,他想参与维护 fx, 我简单看了他的Github主页了之后,就直接把他放到了 collaborator list 去了,后来他直接发了一个很大的 [Pull Request](https://github.com/metrue/fx/pull/100/files)过来,就是用 gRPC 替换了 websocket 的,我当然就很开心的做了merge.
1219
-
1220
- 所以现在的 fx 是一个基于 gRPC 框架的工具. 提供三个核心功能:
1221
-
1222
- ```shell
1223
- Usage:
1224
- $ fx up func1 func2 ... deploy a function or a group of functions
1225
- $ fx down func1 func2 ... destroy a function or a group of functions
1226
- $ fx list list deployed services
1227
- ```
1228
-
1229
- 所以整个架构也很简单,fx up 会将 function 的定义内容传递给 fx server,fx server 接受到 function 的内容了之后,匹配到正确的 Dockerfile 和对应的构建镜像所需的资源, 然后会调用 Docker Engine 的 api 去构建相应的服务,最后把生成的服务的 URL 返回给客户端.
1230
-
1231
- ```shell
1232
- up/ deploy a function to service
1233
- -------------------------------------->
1234
- <--------------------------------------
1235
- down/ stop functions' services
1236
- -------------------------------------->
1237
- fx client <-------------------------------------- fx server
1238
-
1239
- list/ list deployed services
1240
- -------------------------------------->
1241
- <--------------------------------------
1242
- ```
1243
-
1244
- ## fx 支持哪些编程语言
1245
-
1246
- 由于 fx 的一个服务的背后都是一个 Docker Container, 所以 fx 几乎可以支持所有的编程语言,由于精力有限,目前 fx 支持这些编程语言:
1247
- * Golang
1248
- * JavaScript/Node
1249
- * Ruby
1250
- * Python
1251
- * Java
1252
- * PHP
1253
- * Julia
1254
-
1255
- ## fx 的未来
1256
-
1257
- 啥未来,就是一个小工具而已。
1258
- ]]></content>
1259
- <published>2017-10-22T17:42:13.233Z</published>
1260
- </entry>
1261
- <entry>
1262
- <title>记一次大规模重构</title>
1263
- <link href="https://blog.minghe.me/blog/a-complex-web-app-refactor"/>
1264
- <updated>2017-07-05T10:17:04.233Z</updated>
1265
- <id>https://blog.minghe.me/blog/a-complex-web-app-refactor</id>
1266
- <content type="html"><![CDATA[---
1267
- title: 记一次大规模重构
1268
- date: 2017-07-05T10:17:04.233Z
1269
- ---
1270
-
1271
- ## 前言
1272
- 一个健康发展的项目,是不应该有大规模重构的。一个健康的项目,它随时随地的进行着一些小规模的重构,循序渐进,不断改进,积少成多,不断保持项目的活力。但是现实情况是: 我们安逸于现状这样子,虽然它有一些小问题,但是我想我们能够忍受,我们的项目成员不想/敢做出改变,因为它(可能)会触发一些问题。直到有一天,我们不能忍了,因为我们离主流的技术已经很远,我们目前不能使用好的技术方案,我们的开发效率已经太低,我们有很多 bug 不能合理修复,就算修复也可能会带来更多的 bug。所以我们决定来一次大的重构。
1273
-
1274
- 因为我们都这样:小毛小病的,没有什么大碍。直到病入骨髓了,我们痛下决心,做一个大手术。其实小毛小病,生活注意一下,或者吃两服药,就可以药到病除,然后手术却没有那么轻松,如果运气不好,轻则留下浅浅伤疤,重则可能危及生命。就算手术顺利,也需要好长的一段恢复期啊。
1275
-
1276
- 但是如果真要进行一次大手术,我们应该要怎么做才能平安度过呢?说说我自己的真实故事吧。
1277
-
1278
- ## 动手术
1279
- 我上个月来到现在的设计家上海团队。我的第一个大任务: 前端代码的分拆。设计家的整个前端是一个超复杂的 Web 应用,单单是 JavaScript 的代码行数就超过了 20w 行,不包含第三方库。在没有做任何的代码分离之前,我们所有的代码都是放在一起的,包括应用的核心框架,图形的底层操作API,业务组件(UI及业务逻辑)都放在一起。由于历史的原因,不同时期的代码不仅风格迥异,而且打包工具也不统一。这样的一个巨大的混杂的代码库会导致很多问题, 比如
1280
-
1281
- * 构建工具复杂
1282
- * 构建时间长
1283
- * 测试代码难度很大
1284
- * 引入新技术阻力很大
1285
-
1286
- 等等这些可见的问题,还是一些隐藏的问题,比如不同的代码风格,到沟通成本上升。各模块之间的依赖交错复杂等等。
1287
-
1288
- 经过一个月的努力,终于把一个超级巨无霸单一项目分拆成了五个独立的项目,一个主项目(主要是网站的业务代码,是整个 3D 设计家的入口), 以及一个核心库项目(它是整个 3D 设计家的框架层代码),还有其他三个小的基础 API 项目,除了主项目,其他的项目都以 npm 包的形式为外界提供服务。每个项目自己的构建方式对外界透明的。
1289
-
1290
- ### 代码层
1291
- 在进行分拆模块的时候,如下因素.
1292
-
1293
- * 是否和业务无关
1294
- * 是否可以复用
1295
-
1296
- 显然框架层面的代码最应该被独立出来,因为它的接口必须保持一定的稳定性,而且和业务逻辑完全无关,当然它的特殊的构建方式也让我第一时间把它分拆了出来成为独立的项目,对外以提供 npm 包的形式服务。这样我就可以第一时间在主项目中使用统一的构建工具来完成构建 (webpack)。
1297
-
1298
- 其次,一些提供特殊功能的组件,比如数学计算,图形操作等这类基础的 API,也立即被提出来。同类型的还有一些有着代理作用的代码,它们连接着我们团队的主项目和其他团队的库,这些代码通常被不同团队的开发者改动。
1299
-
1300
- 最后主项目就变成了一个纯业务逻辑的项目,主要进行各种功能的维护,新 feature 的开发,是最为 Active 的代码。而分离出去的项目都以独立的 npm 包为外界提供服务,它们的开发较为稳定一些,而不同的项目可以按照团队的技术选择进行多样化的开发,这样在独立项目以上可以多样化技术选择,而同一个项目内部则保持统一的,这样就既兼容了稳定性,而又保持了技术的良好更新迭代。
1301
-
1302
- ### CI/CD 层
1303
- 由于项目的拆分,如何保证各个项目中的代码依赖能够保持同步,保证开发效率的同时能够项目能够保持很好的持续集成和持续部署成为了我们首要解决的问题。
1304
-
1305
- #### 自动构建
1306
- 分离出去的独立项目,它们的发布行为就演变成了一个 npm 包的自动构建和发布。为了保证项目稳定,每一个分离出去的独立项目都采用 release 和 develop 两种形式的 npm 版本特征,它们分别对应的项目的 releae 和 master 分支。当 master 有新的提交的时候,项目在 CI/CD 系统自动构建然后发布 x.y.z-develop-build-number 这样版本的 npm 包,同理,如果是 release 有新的提交,则会自动发布 x.y.z-release-build-number 这样版本的 npm 包。
1307
-
1308
- #### 关联触发
1309
- 经过分拆之后,我们项目由原来的一个巨大的 A, 变成了五个小 a.
1310
-
1311
- ```
1312
- Super Big A => (a1, a2, a3, a4, a5)
1313
- ```
1314
-
1315
- 那么显然,任何小的项目(a2, a3, a4, a5)有更新的时候,我们都必须要触发主项目 (a1) 的构建和并且进行相关的自动化测试。所以在我们的 CI/CD 系统中,我们在 Jenkins 的 job 配置中进行了项目的关连触发。并且主项目(a1)的构建会根据当前所在的 branch (release 还是 master)自动安装与其对应的其他项目(a2, a3, a4,a5)的最新依赖包。然后进行构建和自动部署到对应的开发环境(alpha) 或者生产环境。
1316
-
1317
- ## 反思
1318
- 这次的大手术,整体来说结果是好的,虽然其中遇到了不少的问题,但是趟过了这些坑之后,也让我自己在更多的方面了解了自己,了解了团队,与此同时在提醒自己在哪些地方需要努力。我自己总结了下面几点我们没有做好的地方:
1319
-
1320
- * 让一个项目新手来独立完成
1321
-
1322
- 团队选择刚刚加入团队的我来进行这次大手术,确实不能说是一个正确的选择。虽然我自己对于大型前端的架构有一定架构能力,而且对于主流的构建工具也很熟悉。但是项目的重构不是一个小手术,我们需要一个对整个项目都十分熟悉的人来进行主导,而且最好能够有一个得力的助手来一起完成。因为任何的项目都有很多隐含的坑,特别这种需要大手术的项目,很多的坑稍微一动还有可能会致命,只有对项目十分熟悉的人,才能够知道如何避开(或者直接解决)哪些坑而不耽误重构。
1323
- 当然,项目组最开始是安排了对项目了解最深的工程师来和我一起来进行的,不过进行到一半的时候,他离开了团队,最后只得我一个人来进行。这是一个谁也没有想到的意外。所以当重构的过程中,如果出现任何的问题,我几乎都会花两倍的时间去解决问题,因为我首先需要去知道到底为什么出现问题,原来采用什么方法来解决,现在我需要选择什么替代的方法来解决。更糟糕的是,我现在需要花大量的时间去和其他不固定的同事去沟通来保证各个模块在重构的过程不受到伤害。
1324
-
1325
- * 没有设定好重构的目标
1326
-
1327
- 在进行这次重构,我们并没有设立一个可以量化的目标,我们仅仅只是有这么一个愿景: 重构之后,项目还能和以前一样运转正常,并且开发效率能有所提高。但是这样一个笼统的希望对于整个重构没有任何帮助。我们需要设定一个可以量化的目标,比如所有的测试不能被破坏,构建的时间不能超过10分钟,构建工具必须统一等等。
1328
-
1329
- * 没有测试
1330
-
1331
- 这是一个老生常谈的问题了,没有完备的测试,每一次的改动都会让你惊心胆战。因为你很难确定你的改动会不会造成什么伤害。这也是后续我们希望可以在团队中推广的,也许每一次的开发都做到 TDD 很难,但是必要的单元测试希望可以做到。
1332
-
1333
- * 没有做到完全的沟通
1334
-
1335
- 由于项目的重构会影响到每一个开发者,所以最好让我们一个团队成员都能够理解到这次改动可能造成的影响,不然出现任何的问题,很多人都会感觉很意外,而且束手无策,这样无疑对于重构产生的问题的处理没有任何帮助,而且可能会雪上加霜。
1336
-
1337
- 虽然遇到了不少问题,甚至可能有的同事可能会反感:项目运行的好好的,干嘛搞事情啊。但是总体的结果是好的,这不仅对于让我们项目更加健康的发展做好了很好的基础,而且在今后也会大大的提高我们的开发效率,同时保证产品的快速稳定迭代。
1338
- ]]></content>
1339
- <published>2017-07-05T10:17:04.233Z</published>
1340
- </entry>
1341
- <entry>
1342
- <title>深入浅出Redux的异步Actions</title>
1343
- <link href="https://blog.minghe.me/blog/async-action-in-redux"/>
1344
- <updated>2016-10-17T09:13:34.000Z</updated>
1345
- <id>https://blog.minghe.me/blog/async-action-in-redux</id>
1346
- <content type="html"><![CDATA[---
1347
- title: 深入浅出Redux的异步Actions
1348
- comments: true
1349
- date: 2016-10-17 09:13:34
1350
- updated: 2016-10-17 09:13:34
1351
- tags: Redux
1352
- categories: frontend
1353
- ---
1354
-
1355
- Redux 是一个超棒的 state 容器,它几乎已经成为了 React 前端项目的必备 state 管理库,当然 Redux 可以用于任何应用 JavaScript 应用中,让我们看看这个很棒的库的代码情况吧。
1356
-
1357
- ```
1358
- ➜ src git:(master) ✗ pwd
1359
- /Users/ming/Codes/redux/src
1360
- ➜ src git:(master) ✗ cloc .
1361
- 7 text files.
1362
- 7 unique files.
1363
- 0 files ignored.
1364
-
1365
- http://cloc.sourceforge.net v 1.65 T=0.03 s (212.3 files/s, 18136.0 lines/s)
1366
- -------------------------------------------------------------------------------
1367
- Language files blank comment code
1368
- -------------------------------------------------------------------------------
1369
- Javascript 7 62 199 337
1370
- -------------------------------------------------------------------------------
1371
- SUM: 7 62 199 337
1372
- -------------------------------------------------------------------------------
1373
- ```
1374
-
1375
- 这么棒的东西, 其实就几百行代码而已,不到两个小时你就几乎可以阅读完了,当然要深入理解其理念,还是需要一些时间的,让我们慢慢来。
1376
-
1377
- ### 基本
1378
-
1379
- ```
1380
- import { createStore } from 'redux'
1381
-
1382
- function counter(state = 0, action) {
1383
- switch (action.type) {
1384
- case 'INCREMENT':
1385
- return state + 1
1386
- case 'DECREMENT':
1387
- return state - 1
1388
- default:
1389
- return state
1390
- }
1391
- }
1392
-
1393
- let store = createStore(counter)
1394
-
1395
- store.subscribe(() =>
1396
- console.log(store.getState())
1397
- )
1398
- store.dispatch({ type: 'INCREMENT' })
1399
- // 1
1400
- store.dispatch({ type: 'INCREMENT' })
1401
- // 2
1402
- store.dispatch({ type: 'DECREMENT' })
1403
- ```
1404
-
1405
- 这就是一个很完整的基于 Redux 的 JavaScript 应用了, 我们可以看到这是一个 Counter, 这个 Counter 可以进行 INCREMENT, DECREMENT 操作。 这不是就是简单的观察者模式吗,有人可能会说,是的,其实就是一个简单的观察者模式。还有一些有经验的工程师可能会说,这代码完全没有办法重用和拓展啊,别急,我们慢慢来。
1406
-
1407
- 让我们简单重构一下我们的代码吧:
1408
-
1409
- reducer.js
1410
-
1411
- ```
1412
- const initState = 0;
1413
-
1414
- export default function reducer(state = initState, action) {
1415
- switch (action.type) {
1416
- case 'INCREMENT':
1417
- return state + 1
1418
- case 'DECREMENT':
1419
- return state - 1
1420
- default:
1421
- return state
1422
- }
1423
- }
1424
- ```
1425
-
1426
- actions.js
1427
-
1428
- ```
1429
- export function incr() {
1430
- return {
1431
- type: 'INCREMENT',
1432
- };
1433
- }
1434
-
1435
- export function decr() {
1436
- return {
1437
- type: 'DECREMENT',
1438
- }
1439
- }
1440
- ```
1441
-
1442
- main.js
1443
-
1444
- ```
1445
- import { createStore } from 'redux'
1446
-
1447
- let store = createStore(counter)
1448
- store.subscribe(() =>
1449
- console.log(store.getState())
1450
- )
1451
- store.dispatch({ type: 'INCREMENT' })
1452
- // 1
1453
- store.dispatch({ type: 'INCREMENT' })
1454
- // 2
1455
- store.dispatch({ type: 'DECREMENT' })
1456
- ```
1457
- 这样是不是感觉熟悉了很多呢,很多时候,简单遵循一些原则,代码就好看很多,比如这里的单一责任原则(Single responsibility principle).
1458
-
1459
- 从上面的代码可以看到,我们的 actions 全都是返回 plain object 的 function, 因为 store 只能 dispatch 纯的 Object, 而且携带这 type 属性。那么当我们有 actions 是的异步的怎么呢,比如我们有一个 ADD 的 action, 需要先去取到一个 value 然后才能进行添加操作,那么我们应该怎么做呢?
1460
-
1461
- ### 异步 actions
1462
-
1463
- ```
1464
- function add(value) {
1465
- return {
1466
- type: 'ADD',
1467
- value,
1468
- }
1469
- }
1470
-
1471
- function fetchValue() {
1472
- return new Promise((resolve) => {
1473
- setTimeout(() => {
1474
- resolve(2)
1475
- }, 1000)
1476
- })
1477
- }
1478
-
1479
- function asyncAdd() {
1480
- return function(dispatch) {
1481
- fetchValue().then((val) => {
1482
- dispatch(add(val))
1483
- });
1484
- }
1485
- }
1486
-
1487
- ```
1488
-
1489
- 可以看到,我们在 dispatch 这个 add action之前,需要先得到需要 add 的 value, 而这个 value 的获取是异步的。所以我需要 dispatch 的是 asyncAdd() 这个 action, 但是这个 action 返回不是一个 plain object, 而是一个 function, 那么我们怎么才能让 store 能够直接 dispatch 一个 function 呢,我们需要一个中间件。
1490
-
1491
- Redux 提供了 redux-thunk 这个中间件来帮组我们做这件事情。
1492
-
1493
- ```
1494
- import { createStore, applyMiddleware } from 'redux'
1495
-
1496
- const store = createStore(redux, applyMiddleware(thunk));
1497
- store.dispatch(asyncAdd());
1498
- ```
1499
-
1500
- 可以看到我们 dispatch 了一个返回 function 的 action, 这个返回的 function 接收 dispatch 作为参数,在进行了异步操作之后, dispatch 一个 type 为了 ADD 的 action, 这个action 会被 reducer 捕捉然后更新 store. 一句话来总结 redux-thunk 的作用,那就是: 让 store 可以 dispatch 一个 function, 而不仅仅是 plain object.
1501
-
1502
- 对于简单的应用来, redux-thunk 也许可以完全胜任我们对于异步 action 的需求,但是它有着很明显的问题:
1503
-
1504
- * actions 不在仅仅是一些返回 plain object 的function.
1505
- * dispatch 散落在不同的地方
1506
- * 测试变得复杂
1507
-
1508
- 是否可以有一种更友好进步的方式来管理异步 action 呢,所有 dispatch 出来的 action, 实际上都是广播形式,所有 store 的 listeners 都可以监听到,那么我们就可以让中间件去处理集中管理所有的异步操作, 等到特定结果的时候才 dispatch 相应的结果 action 出来,reducer 监听特定的 actions 去做 state 的更新操作, 这就是 redux-saga 这个第三方中间件的作用.
1509
-
1510
- saga.js
1511
-
1512
- ```
1513
- import { takeEvery } from 'redux-saga'
1514
- import { put } from 'redux-saga/effects'
1515
-
1516
- function* addWorker() {
1517
- const value = yield call([fetchValue]);
1518
- yield put({ type: 'ADD_SUCCESS', value });
1519
- }
1520
-
1521
- function* addWatcher() {
1522
- yield* takeEvery('ADD', addWorker);
1523
- }
1524
-
1525
- export default addWatcher;
1526
- ```
1527
-
1528
- main.js
1529
-
1530
- ```
1531
- const sagaMiddleware = createSagaMiddleware();
1532
- const store = createStore(reducer, applyMiddleware(sagaMiddleware));
1533
- sagaMiddleware.run(addWatcher);
1534
- ```
1535
-
1536
- 这个代码,可以让我们处理逻辑就变得十分清晰.
1537
-
1538
- * watcher 监听目标 actions, 然后分发到相应的 worker 去执行
1539
- * worker 负责真正的异步操作,完成之后发布特定的 action 到 reducer
1540
- * actions 全部都是 plain object
1541
-
1542
- 而且我们的代码非常容易进行测试,actions 全是 plain object, 表征应用的行为,而 saga 负责异步调用, 其测试只需要测试 watcher 是否能正确监听 actions, 然后分发到正确的 worker, 而 worker 是否完成异步操作之后发布正确的 action.
1543
-
1544
- 当然这样做有一个不好的地方就是,所有的 action,都会同时被 saga 和 reducer 所监听,所以当你的 actions 设计不当,容易造成循环依赖。这个问题曾经在我的项目出现过一次,debug 起来较为麻烦, 所以在设计 actions 的时候一定要区分好那些 action 是 reducer 去 handle, 而那些 actions 是 saga 去 handle.
1545
-
1546
- ### 测试
1547
- 其实关于 redux-saga 的测试,估计很少有人写,因为其实用 redux-saga 的其实应该不多, 更多人应该用 redux-thunk, 但其实 redux-thunk 很多人也没有写测试吧, 让我们来看看如何优雅的写好 redux-saga 的单元测试吧。
1548
-
1549
- ```
1550
- function constructExpectCallReturn(func, args) {
1551
- return (
1552
- {
1553
- '@@redux-saga/IO': true,
1554
- CALL: {
1555
- context: {
1556
- server: 'http://localhost:3000',
1557
- baseURL: 'http://localhost:3000/v1',
1558
- },
1559
- fn: func,
1560
- args,
1561
- },
1562
- }
1563
- );
1564
- }
1565
-
1566
- describe('watcher', () => {
1567
- const action = { type: 'ADD' };
1568
-
1569
- it('should take on ADD action ', () => {
1570
- actualYield = addWatcher.next().value;
1571
- expectedYield = take(ADD, addWorker);
1572
- expect(expectedYield).to.eql(actualYield);
1573
- });
1574
-
1575
- it('should fork the saga handler with action', () => {
1576
- expectedYield = fork(addWorker, action);
1577
- actualYield = addWatcher.next(action).value;
1578
- expect(expectedYield).to.eql(actualYield);
1579
- });
1580
-
1581
- it('should return to capturing the FETCH action again', () => {
1582
- actualYield = addWatcher.next().value;
1583
- expectedYield = take(ADD, addWorker);
1584
- expect(actualYield).to.eql(expectedYield);
1585
- });
1586
- });
1587
-
1588
- describe('worker', () => {
1589
- it('should handle add', () => {
1590
- const action = { type: ADD };
1591
- const addIterator = addWorker(action);
1592
-
1593
- expectedYield = constructExpectCallReturn(fetchValue, []);
1594
- actualYield = addIterator.next().value;
1595
- expect(expectedYield).to.eql(actualYield);
1596
- });
1597
- });
1598
-
1599
- ```
1600
-
1601
- 可以看到我们的代码完全是可测试, 而且责任分的十分清楚,模块化程度十分高。
1602
- 上面的代码都是在非 React 的应用中,可以看出我的初衷,也就是 Redux 其实适用于所有的 JavaScript 应用,当然在 React 中,更是缺之不可啊,当然用这些优秀工具的同时,我们更重要的是理解其中的理念,知道这样做,也要知道为什么需要这样做,这样我们才能在没有这些东西的时候,我们如何解构我们的代码,甚至是做出自己的类 Redux, 类 redux-thunk, redux-saga 的工具。
1603
- ]]></content>
1604
- <published>2016-10-17T09:13:34.000Z</published>
1605
- </entry>
1606
- <entry>
1607
- <title>逛逛济州岛</title>
1608
- <link href="https://blog.minghe.me/blog/%E9%80%9B%E9%80%9B%E6%B5%8E%E5%B7%9E%E5%B2%9B"/>
1609
- <updated>2015-06-28T09:20:02.322Z</updated>
1610
- <id>https://blog.minghe.me/blog/%E9%80%9B%E9%80%9B%E6%B5%8E%E5%B7%9E%E5%B2%9B</id>
1611
- <content type="html"><![CDATA[---
1612
- title: 逛逛济州岛
1613
- date: 2015-06-28T09:20:02.322Z
1614
- ---
1615
-
1616
-
1617
- 一些朋友听说我们来济州岛学习驾驶并且已经结束了之后,都希望我可以写一篇攻略,然而我都已经忘记了自己什么时候决定要来济州岛学习驾驶,也忘记了怎么就糊里糊涂选了这个团。所以攻略基本上只有这几点:
1618
-
1619
- * 选择一家合适的中介
1620
-
1621
- * 带一件外套
1622
-
1623
- * 考试的时候不要紧张
1624
-
1625
- 那么你一定可以很顺利的就可以完成你的驾驶学习, 拿到一张韩国驾照,一张国际驾照,并且你一定可以自己上路开车了。回到国内之后去车管所预约考科目一,过一周左右之后就可以直接考试,通过之后现场拿国内驾照.
1626
-
1627
- 好吧,关于济州岛学习驾驶我想说的只有这么多,我还是来说说我的这次旅行吧。
1628
-
1629
-
1630
- ### 济州岛 的海
1631
-
1632
- 海水很冷,海风很爽,海浪很白; 海边的石头很多形状,海边的灯光很温暖,海边的公路很长,海边的人很安静。
1633
-
1634
- 你需要去海边走一走,踩在石头上,感受一下海水,看看奇怪的小虫,多穿一点衣服是好的,若你和我一样怕冷的话。你会选择在有阳光的下午四五点,漫步在海边的公路上,向左或者向右,随机挑选一个方向。
1635
-
1636
- ```
1637
- 这个方向会决定你在远离什么,在靠近什么.
1638
- ```
1639
-
1640
- 然后任意的走着,等待着夕阳慢慢的洒下来,看看海边的那一片黄色,怕几张照片,选一个好方向,可以看清楚脸或者显高一点的。 晚上可以找一快背后有灯的大石头,拿一瓶啤酒,听听海浪,或者潮,或者汐,拍打石头的声音,聊聊文字和音乐, 想想远方.
1641
-
1642
- ### 济州岛 的城
1643
-
1644
- 当你在海边公路走的时候,如果你选择了右边,那么你会离旧济州比较近,反之,如果你选择了左边,那么你会离新济州比较近。
1645
-
1646
- * 向右
1647
-
1648
- 也许旧济州的生命开始于晚上,白天的旧济州无论是七星街还是地下步行街都很少的人,所以你可以在白天很白痴的在七星街的那台钢琴上乱弹,当然如果你注意你的手型,那么你会发现弹起来还是挺有范儿的,而且仔细一听,原来自己离音乐厅里声音离的挺近多。
1649
-
1650
- 地下步行街有点像上海的七浦路,听说。很多商品,挺干净,人不多,价格适中,也许有你想要的。
1651
-
1652
- 任意选择一个出口走上来之后,或许你会想要去走走看看济州的City Hall,你会沿着路标指示方向去寻找,然而你一定会找不到它在哪儿的。你会走一个有点长的上坡路,你会路过东门市场,那附近有一些听说是 "便衣警察" 的人,然后你会随便走走看看。东门市场会很腥,因为有很多的海产品。然后你会选择一个一条你依然不知道什么目的地的路,然后一直走,直到打上出租车,递上酒店的名片。
1653
-
1654
- * 向左
1655
-
1656
- 新济州有新罗,乐天的免税店,所以你会看到好多的移动 WiFi 有着相同的命名方式,因为他们都来自同一个地方。
1657
-
1658
- 我忘记了我们那天为什么要去一个叫做 Yeon Dong 的地方了,只记得我们搞错了方向,也许是因为我们只知道这个单词 "Yeon Dong",所以我们就到了所谓 Yeon Dong, 这个词的发音很重要,你也许要好好学习一下它的调调,*(_---_)*
1659
-
1660
- 到了市区之后,也许会下雨,也许你还不用打伞,到 CU 选择一个确定自己很能吃下去的食物,比如紫菜包饭, 然后随便石头剪刀布选择一个方向吧,自然而然的走走就好, 随便聊聊天, 看看路和人。
1661
-
1662
- 然后你会绕了一个圈,发现一个星巴克,然后你会发现你很冷,需要一杯摩卡暖暖身,选择一个靠窗的位置,喝几个小时,直到天黑, 然后你会发现你嗓子有点哑了,可以还是感觉很冷,然后继续坐着吧,反正外面的行人还打着伞。
1663
-
1664
- 真的很晚了,好吧,走走没有走过的小街道,找点吃的,当到了某个路口的时候,如果你戴眼镜,你应该可以看到一家中餐厅,而且似乎什么都有,以为是路边破店,进来发现其实很齐整,没有东北口音的女老板,她可以让你发现自己没有韩币的时候返回来刷信用卡,退给你韩币,然后你拿着韩币找 taxi 回海边的酒店。
1665
-
1666
- ### 济州岛 的吃
1667
-
1668
- 济州岛 的吃我没有喜欢。
1669
-
1670
- 不过如果真的要活下去的话,你需要吃一点海鲜类的各式菜式,或者大块的黑猪肉烧烤,也许大酱汤你会习惯,其实大酱汤的大酱是看不见的,如果你和我一样来自中国西南某小城,你应该会惊讶,为什么酱还能看不见。如果你也喜欢喝点汤,那么参鸡汤可以让你解解饿。希望你不是和我一样,只喜欢一种东西,那么你一定不会像我一样自己饿不饿都不知道。
1671
-
1672
- ### 最后
1673
-
1674
- 也许你需要和我一样:
1675
-
1676
- * 考科目三的时候挂一次
1677
-
1678
- * 住在 济州岛 西海岸的 酒店
1679
-
1680
- * 有同样没有方向感的伙伴
1681
-
1682
- * 没有陌生的合群能力
1683
-
1684
- * 航班因天气原因取消一次
1685
-
1686
- 才能够体验这段旅程,然后坐在机场,写下这些文字。
1687
-
1688
- ![JeJuP.jpg](https://github.com/metrue/Cofe/blob/main/assets/images/2025-02-26/1740551428629.jpg?raw=true)]]></content>
1689
- <published>2015-06-28T09:20:02.322Z</published>
1690
- </entry>
1691
15
  </feed>