35 |
36 |
37 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/test/youtube_subs_test.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:test/test.dart';
3 | import 'package:youtube_subs/youtube_subs.dart';
4 |
5 | void main() {
6 | test('runs', () {
7 | final subs = YouTubeSubs.fromString(r'''hello there, it's march 13. i want to give you a little update on the sample flutter game that i'm working on. just so i think it's better to show it in motion at this point rather than, you know, giving you updates in the doc. which, of course, the dock is still open and still updated. all right. so i have it here in uh on an ipad. and here on an android device. and also well i can i can show you later but um i guess the game is for mobile phones so this is probably the the most important a salient part. i'll open it i think i think you can i think you can hear that it has music. i think you can maybe see uh yeah i think you can see what's what's going on there? so we have the play button of course. we have achievements, leaderboards and settings. if i click on leaderboards, for example, i get the leaderboards which currently has one person on it. which is me. and then achievements. i haven't like added actual achievements but it works. it just says there are no achievements right now. cool. all right. so i can go to play. you can hear there's a little bit of uh sound as well. so and and there's also this kind of um custom transition. i can select a level uh which are now... i love the sounds. i i kind of like them. um then uh i mean what was i saying... yeah oh the the music, of course, is um... we have all the the rights to to use it. it's uh cc0 and cc by. but i also have a permission from the author to use it for this particular project, and even include the audio files in the github repository so everyone can use them. and this is great music for these types of games. played on a mobile phone with pretty bad speakers. great great stuff! okay cool. so uh, again, what i wanted to show you is
8 |
9 | that it all works okay. so i'll i'll win a game if i can i can do that.''');
10 | expect(() => subs.render(), returnsNormally);
11 | });
12 | }
--------------------------------------------------------------------------------
/lib/youtube_subs.dart:
--------------------------------------------------------------------------------
1 | import 'package:characters/characters.dart';
2 |
3 | class YouTubeSubs {
4 | final List<_Sentence> sentences;
5 |
6 | YouTubeSubs(this.sentences);
7 |
8 | factory YouTubeSubs.fromString(String string) {
9 | var chars = string.characters;
10 |
11 | var sentences = <_Sentence>[];
12 | var sentenceStart = 0;
13 | for (int i = 0; i < chars.length; i++) {
14 | final char = chars.characterAt(i);
15 | if (_sentenceEndPunctuation.hasMatch(char.string)) {
16 | // Possible end of sentence.
17 | if (chars.length == i + 1 ||
18 | _whitespace.hasMatch(chars.characterAt(i + 1).string)) {
19 | var sentenceChars = chars.getRange(sentenceStart, i);
20 | var sentenceEndPunctuation = char;
21 | sentences.add(
22 | _Sentence.fromCharacters(sentenceChars, sentenceEndPunctuation));
23 | // The punctuation plus the whitespace.
24 | sentenceStart = i + 2;
25 | }
26 | }
27 | }
28 |
29 | return YouTubeSubs(sentences);
30 | }
31 |
32 | Iterable render() sync* {
33 | for (final sentence in sentences) {
34 | yield* sentence.render();
35 | yield ' ';
36 | }
37 | }
38 |
39 | @override
40 | String toString() => 'YouTubeSubs(${sentences.length} sentences)';
41 | }
42 |
43 | class _Sentence {
44 | final List<_Word> words;
45 |
46 | _Sentence(this.words, this.endPunctuation);
47 |
48 | factory _Sentence.fromCharacters(
49 | Characters rawSentence, Characters endPunctuation) {
50 | final words = <_Word>[];
51 |
52 | var wordStart = 0;
53 | for (int i = 0; i < rawSentence.length; i++) {
54 | if (_whitespace.hasMatch(rawSentence.characterAt(i).string)) {
55 | var wordChars = rawSentence.getRange(wordStart, i);
56 |
57 | final isNotEmpty =
58 | wordChars.isNotEmpty && !_whitespace.hasMatch(wordChars.string);
59 | final isNotFillWord = !_fillWords.contains(wordChars.string);
60 | bool isNotRepeatingLastWord = true;
61 | if (words.isNotEmpty) {
62 | if (words.last.text == wordChars) {
63 | isNotRepeatingLastWord = false;
64 | }
65 | }
66 | if (isNotEmpty && isNotFillWord && isNotRepeatingLastWord) {
67 | words.add(_Word(wordChars));
68 | }
69 | // The punctuation plus the whitespace.
70 | wordStart = i + 1;
71 | }
72 | }
73 | var wordChars = rawSentence.getRange(wordStart);
74 | words.add(_Word(wordChars));
75 |
76 | return _Sentence(words, endPunctuation);
77 | }
78 |
79 | Characters endPunctuation;
80 |
81 | Iterable render() sync* {
82 | yield* words.first.render(capitalized: true);
83 |
84 | for (final word in words.skip(1)) {
85 | yield ' ';
86 | yield* word.render();
87 | }
88 |
89 | yield endPunctuation.string;
90 | }
91 | }
92 |
93 | final _sentenceEndPunctuation = RegExp(r'[\!\?\.]+');
94 |
95 | final _whitespace = RegExp(r'^\s+$');
96 |
97 | class _Word {
98 | final Characters text;
99 |
100 | _Word(this.text)
101 | : assert(text.isNotEmpty),
102 | assert(text.characterAt(0).isNotEmpty);
103 |
104 | Iterable render({bool capitalized = false}) sync* {
105 | for (var exception in _specialCapitalization) {
106 | if (exception.toLowerCase() == text.toLowerCase().string) {
107 | yield exception;
108 | return;
109 | }
110 | }
111 |
112 | // Special cases.
113 | final autoAllCaps = _alwaysAllCaps.contains(text.string);
114 | if (autoAllCaps) {
115 | yield text.toUpperCase().string;
116 | return;
117 | }
118 |
119 | final autoCapitalized = _alwaysCapitalized.contains(text.string);
120 | if (capitalized || autoCapitalized) {
121 | yield text.characterAt(0).toUpperCase().string;
122 | } else {
123 | yield text.characterAt(0).string;
124 | }
125 |
126 | yield text.getRange(1).string;
127 | }
128 | }
129 |
130 | const _alwaysCapitalized = [
131 | 'i',
132 | "i'll",
133 | "i'm",
134 | "i'd",
135 | 'mac',
136 | 'apple',
137 | 'google',
138 | 'flutter',
139 | 'android',
140 | 'filip',
141 | 'prague',
142 | 'czech',
143 | 'linux',
144 | 'windows',
145 | 'speedometer',
146 | 'udemy',
147 | ];
148 |
149 | const _alwaysAllCaps = [
150 | 'ide',
151 | 'cpu',
152 | 'ram',
153 | 'usa',
154 | ];
155 |
156 | const _specialCapitalization = [
157 | 'MacBook',
158 | 'JavaScript',
159 | 'Xcode',
160 | 'YouTube',
161 | 'GitHub',
162 | ];
163 |
164 | const _fillWords = [
165 | 'um',
166 | 'uh',
167 | ];
168 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | _fe_analyzer_shared:
5 | dependency: transitive
6 | description:
7 | name: _fe_analyzer_shared
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "38.0.0"
11 | analyzer:
12 | dependency: transitive
13 | description:
14 | name: analyzer
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "3.4.1"
18 | archive:
19 | dependency: transitive
20 | description:
21 | name: archive
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "3.3.0"
25 | args:
26 | dependency: transitive
27 | description:
28 | name: args
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "2.3.0"
32 | async:
33 | dependency: transitive
34 | description:
35 | name: async
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "2.8.2"
39 | bazel_worker:
40 | dependency: transitive
41 | description:
42 | name: bazel_worker
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "1.0.1"
46 | boolean_selector:
47 | dependency: transitive
48 | description:
49 | name: boolean_selector
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "2.1.0"
53 | build:
54 | dependency: transitive
55 | description:
56 | name: build
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "2.2.1"
60 | build_config:
61 | dependency: transitive
62 | description:
63 | name: build_config
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "1.0.0"
67 | build_daemon:
68 | dependency: transitive
69 | description:
70 | name: build_daemon
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "3.0.1"
74 | build_modules:
75 | dependency: transitive
76 | description:
77 | name: build_modules
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "4.0.4"
81 | build_resolvers:
82 | dependency: transitive
83 | description:
84 | name: build_resolvers
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "2.0.6"
88 | build_runner:
89 | dependency: "direct dev"
90 | description:
91 | name: build_runner
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "2.1.8"
95 | build_runner_core:
96 | dependency: transitive
97 | description:
98 | name: build_runner_core
99 | url: "https://pub.dartlang.org"
100 | source: hosted
101 | version: "7.2.3"
102 | build_web_compilers:
103 | dependency: "direct dev"
104 | description:
105 | name: build_web_compilers
106 | url: "https://pub.dartlang.org"
107 | source: hosted
108 | version: "3.2.2"
109 | built_collection:
110 | dependency: transitive
111 | description:
112 | name: built_collection
113 | url: "https://pub.dartlang.org"
114 | source: hosted
115 | version: "5.1.1"
116 | built_value:
117 | dependency: transitive
118 | description:
119 | name: built_value
120 | url: "https://pub.dartlang.org"
121 | source: hosted
122 | version: "8.1.4"
123 | characters:
124 | dependency: "direct main"
125 | description:
126 | name: characters
127 | url: "https://pub.dartlang.org"
128 | source: hosted
129 | version: "1.2.0"
130 | charcode:
131 | dependency: transitive
132 | description:
133 | name: charcode
134 | url: "https://pub.dartlang.org"
135 | source: hosted
136 | version: "1.3.1"
137 | checked_yaml:
138 | dependency: transitive
139 | description:
140 | name: checked_yaml
141 | url: "https://pub.dartlang.org"
142 | source: hosted
143 | version: "2.0.1"
144 | code_builder:
145 | dependency: transitive
146 | description:
147 | name: code_builder
148 | url: "https://pub.dartlang.org"
149 | source: hosted
150 | version: "4.1.0"
151 | collection:
152 | dependency: transitive
153 | description:
154 | name: collection
155 | url: "https://pub.dartlang.org"
156 | source: hosted
157 | version: "1.16.0"
158 | convert:
159 | dependency: transitive
160 | description:
161 | name: convert
162 | url: "https://pub.dartlang.org"
163 | source: hosted
164 | version: "3.0.1"
165 | coverage:
166 | dependency: transitive
167 | description:
168 | name: coverage
169 | url: "https://pub.dartlang.org"
170 | source: hosted
171 | version: "1.2.0"
172 | crypto:
173 | dependency: transitive
174 | description:
175 | name: crypto
176 | url: "https://pub.dartlang.org"
177 | source: hosted
178 | version: "3.0.1"
179 | dart_style:
180 | dependency: transitive
181 | description:
182 | name: dart_style
183 | url: "https://pub.dartlang.org"
184 | source: hosted
185 | version: "2.2.2"
186 | file:
187 | dependency: transitive
188 | description:
189 | name: file
190 | url: "https://pub.dartlang.org"
191 | source: hosted
192 | version: "6.1.2"
193 | fixnum:
194 | dependency: transitive
195 | description:
196 | name: fixnum
197 | url: "https://pub.dartlang.org"
198 | source: hosted
199 | version: "1.0.0"
200 | frontend_server_client:
201 | dependency: transitive
202 | description:
203 | name: frontend_server_client
204 | url: "https://pub.dartlang.org"
205 | source: hosted
206 | version: "2.1.2"
207 | glob:
208 | dependency: transitive
209 | description:
210 | name: glob
211 | url: "https://pub.dartlang.org"
212 | source: hosted
213 | version: "2.0.2"
214 | graphs:
215 | dependency: transitive
216 | description:
217 | name: graphs
218 | url: "https://pub.dartlang.org"
219 | source: hosted
220 | version: "2.1.0"
221 | http_multi_server:
222 | dependency: transitive
223 | description:
224 | name: http_multi_server
225 | url: "https://pub.dartlang.org"
226 | source: hosted
227 | version: "3.2.0"
228 | http_parser:
229 | dependency: transitive
230 | description:
231 | name: http_parser
232 | url: "https://pub.dartlang.org"
233 | source: hosted
234 | version: "4.0.0"
235 | io:
236 | dependency: transitive
237 | description:
238 | name: io
239 | url: "https://pub.dartlang.org"
240 | source: hosted
241 | version: "1.0.3"
242 | js:
243 | dependency: transitive
244 | description:
245 | name: js
246 | url: "https://pub.dartlang.org"
247 | source: hosted
248 | version: "0.6.4"
249 | json_annotation:
250 | dependency: transitive
251 | description:
252 | name: json_annotation
253 | url: "https://pub.dartlang.org"
254 | source: hosted
255 | version: "4.4.0"
256 | lints:
257 | dependency: "direct dev"
258 | description:
259 | name: lints
260 | url: "https://pub.dartlang.org"
261 | source: hosted
262 | version: "1.0.1"
263 | logging:
264 | dependency: transitive
265 | description:
266 | name: logging
267 | url: "https://pub.dartlang.org"
268 | source: hosted
269 | version: "1.0.2"
270 | matcher:
271 | dependency: transitive
272 | description:
273 | name: matcher
274 | url: "https://pub.dartlang.org"
275 | source: hosted
276 | version: "0.12.11"
277 | meta:
278 | dependency: transitive
279 | description:
280 | name: meta
281 | url: "https://pub.dartlang.org"
282 | source: hosted
283 | version: "1.7.0"
284 | mime:
285 | dependency: transitive
286 | description:
287 | name: mime
288 | url: "https://pub.dartlang.org"
289 | source: hosted
290 | version: "1.0.1"
291 | node_preamble:
292 | dependency: transitive
293 | description:
294 | name: node_preamble
295 | url: "https://pub.dartlang.org"
296 | source: hosted
297 | version: "2.0.1"
298 | package_config:
299 | dependency: transitive
300 | description:
301 | name: package_config
302 | url: "https://pub.dartlang.org"
303 | source: hosted
304 | version: "2.0.2"
305 | path:
306 | dependency: transitive
307 | description:
308 | name: path
309 | url: "https://pub.dartlang.org"
310 | source: hosted
311 | version: "1.8.1"
312 | pool:
313 | dependency: transitive
314 | description:
315 | name: pool
316 | url: "https://pub.dartlang.org"
317 | source: hosted
318 | version: "1.5.0"
319 | protobuf:
320 | dependency: transitive
321 | description:
322 | name: protobuf
323 | url: "https://pub.dartlang.org"
324 | source: hosted
325 | version: "2.0.1"
326 | pub_semver:
327 | dependency: transitive
328 | description:
329 | name: pub_semver
330 | url: "https://pub.dartlang.org"
331 | source: hosted
332 | version: "2.1.1"
333 | pubspec_parse:
334 | dependency: transitive
335 | description:
336 | name: pubspec_parse
337 | url: "https://pub.dartlang.org"
338 | source: hosted
339 | version: "1.2.0"
340 | scratch_space:
341 | dependency: transitive
342 | description:
343 | name: scratch_space
344 | url: "https://pub.dartlang.org"
345 | source: hosted
346 | version: "1.0.1"
347 | shelf:
348 | dependency: transitive
349 | description:
350 | name: shelf
351 | url: "https://pub.dartlang.org"
352 | source: hosted
353 | version: "1.2.0"
354 | shelf_packages_handler:
355 | dependency: transitive
356 | description:
357 | name: shelf_packages_handler
358 | url: "https://pub.dartlang.org"
359 | source: hosted
360 | version: "3.0.0"
361 | shelf_static:
362 | dependency: transitive
363 | description:
364 | name: shelf_static
365 | url: "https://pub.dartlang.org"
366 | source: hosted
367 | version: "1.1.0"
368 | shelf_web_socket:
369 | dependency: transitive
370 | description:
371 | name: shelf_web_socket
372 | url: "https://pub.dartlang.org"
373 | source: hosted
374 | version: "1.0.1"
375 | source_map_stack_trace:
376 | dependency: transitive
377 | description:
378 | name: source_map_stack_trace
379 | url: "https://pub.dartlang.org"
380 | source: hosted
381 | version: "2.1.0"
382 | source_maps:
383 | dependency: transitive
384 | description:
385 | name: source_maps
386 | url: "https://pub.dartlang.org"
387 | source: hosted
388 | version: "0.10.10"
389 | source_span:
390 | dependency: transitive
391 | description:
392 | name: source_span
393 | url: "https://pub.dartlang.org"
394 | source: hosted
395 | version: "1.8.2"
396 | stack_trace:
397 | dependency: transitive
398 | description:
399 | name: stack_trace
400 | url: "https://pub.dartlang.org"
401 | source: hosted
402 | version: "1.10.0"
403 | stream_channel:
404 | dependency: transitive
405 | description:
406 | name: stream_channel
407 | url: "https://pub.dartlang.org"
408 | source: hosted
409 | version: "2.1.0"
410 | stream_transform:
411 | dependency: transitive
412 | description:
413 | name: stream_transform
414 | url: "https://pub.dartlang.org"
415 | source: hosted
416 | version: "2.0.0"
417 | string_scanner:
418 | dependency: transitive
419 | description:
420 | name: string_scanner
421 | url: "https://pub.dartlang.org"
422 | source: hosted
423 | version: "1.1.0"
424 | term_glyph:
425 | dependency: transitive
426 | description:
427 | name: term_glyph
428 | url: "https://pub.dartlang.org"
429 | source: hosted
430 | version: "1.2.0"
431 | test:
432 | dependency: "direct main"
433 | description:
434 | name: test
435 | url: "https://pub.dartlang.org"
436 | source: hosted
437 | version: "1.20.2"
438 | test_api:
439 | dependency: transitive
440 | description:
441 | name: test_api
442 | url: "https://pub.dartlang.org"
443 | source: hosted
444 | version: "0.4.9"
445 | test_core:
446 | dependency: transitive
447 | description:
448 | name: test_core
449 | url: "https://pub.dartlang.org"
450 | source: hosted
451 | version: "0.4.11"
452 | timing:
453 | dependency: transitive
454 | description:
455 | name: timing
456 | url: "https://pub.dartlang.org"
457 | source: hosted
458 | version: "1.0.0"
459 | typed_data:
460 | dependency: transitive
461 | description:
462 | name: typed_data
463 | url: "https://pub.dartlang.org"
464 | source: hosted
465 | version: "1.3.0"
466 | vm_service:
467 | dependency: transitive
468 | description:
469 | name: vm_service
470 | url: "https://pub.dartlang.org"
471 | source: hosted
472 | version: "8.2.2"
473 | watcher:
474 | dependency: transitive
475 | description:
476 | name: watcher
477 | url: "https://pub.dartlang.org"
478 | source: hosted
479 | version: "1.0.1"
480 | web_socket_channel:
481 | dependency: transitive
482 | description:
483 | name: web_socket_channel
484 | url: "https://pub.dartlang.org"
485 | source: hosted
486 | version: "2.1.0"
487 | webkit_inspection_protocol:
488 | dependency: transitive
489 | description:
490 | name: webkit_inspection_protocol
491 | url: "https://pub.dartlang.org"
492 | source: hosted
493 | version: "1.0.0"
494 | yaml:
495 | dependency: transitive
496 | description:
497 | name: yaml
498 | url: "https://pub.dartlang.org"
499 | source: hosted
500 | version: "3.1.0"
501 | sdks:
502 | dart: ">=2.16.1 <3.0.0"
503 |
--------------------------------------------------------------------------------
/example/example.txt:
--------------------------------------------------------------------------------
1 | no. the answer is no. at least in my opinion. but let's get to it first.
2 |
3 | look, i am a cheapo. i i wear inexpensive clothes. i drive used, you know, toyota. this office is one of the cheapest in the city. the the the furniture that you see here, all the furniture here, is something that they wanted to throw away. and i was like, can you give it to me instead? and they were like, yeah, sure. and so so yeah, i am a cheap person.
4 |
5 | but, i don't mind spending money for things that i find important. especially equipment. i have a business here. i'm a lecturer and a game developer, and of course i understand that businesses have expenses expenses. i like the analogy with farmers and tractors, right? so so if i didn't have a software development and lecturing business, and instead i had an agricultural business, i would be buying a tractor once in a while. and tractors, i learned today, are pretty expensive. like fifty thousand dollars for a used, but still pretty high-end, tractor, apparently. that's that's pretty expensive. but if you want to do your job well, you sometimes need a tractor. and and that tractor, you probably don't want to be too cheap about the tractor because it's something that you will be using eight hours a day at least. it needs to do all the things. it needs to be reliable and stuff. so, the same way that i would be buying good tractors if i were a farmer, i don't mind spending money for equipment that lets me be a good developer. like a computer!
6 |
7 | so when i learned that there is a new machine on the market that has, in some ways, unprecedented computing power, i was like: i'm listening. and i'm of course talking about the new Mac Studio with the M1 Ultra chip. and then someone said that "this thing right here is literally the best mac ever made for programming".
8 |
9 | i was ready to investigate. when there is a new tractor on the market that is apparently the best for the job that i'm trying to do then i should probably look into it. so, the first thing that i did was i looked at YouTube videos. not the apple event because that's basically like a one hour long advertisement. "Mac Studio is a breakthrough".
10 | "M1 Ultra is the next breakthrough". "Silicon enables us to provide experiences that no one else can". But on people who are reviewing stuff. and i looked at them and their benchmarks, and i spent a good, i don't know, half an hour, maybe, or even more, just kind of looking at youtube videos, getting excited. then i realized, okay, so this is a lot of money. i should probably be a lot more analytical. and so this video is about my process of thinking about it, in an analytical sense. and how i went about it. in the end, i realized that the Mac Studio with the Ultra chip is not worth it. definitely not for me, and i would wager that not for most developers out there. and then i was like, did i just spend four hours of my day trying to get to this conclusion? and, like, making spreadsheets and watching videos and doing benchmarks and so on? so, i realized, okay what i'll do, is: i'll spend another four hours, at least, making a video about it. just, like and subscribe okay?
11 |
12 | first, let's talk about why even choose a mac at all for software development. and i'm not trying to persuade anyone about anything. and i realize that this is a topic for more than a single video even, let alone just a part of a video. but i just want to dispel the myth that macs are used only because of marketing. only because of the shininess of this thing. that's not true.
13 |
14 | to be honest, this myth is not completely unfounded, right? apple spends a ton of money for marketing, and they are known for bending the facts in order to tell the narrative that, you know, apple products are best at everything, and they were the first to do everything, and they're like super innovative and stuff like this. which is not always the truth.
15 |
16 | it does make sense to be very wary of anything that apple is trying to sell you.
17 |
18 | but i have a very real comparison here. about three years ago i needed to buy a new development computer for personal use. i used, you know, i was employed at google, so obviously i had no trouble having a development computer for work. but for personal use, i didn't have anything, and i decided to go for a window / linux laptop. and i also decided to go for the top of the line of those things, right? so i spent a lot of money. my windows / linux laptop is almost two times more expensive than my current macbook so it's not like... i hate it when sometimes people compare, you know, a $800 windows laptop with a $2,000 macbook pro, and they're like, oh, the macbook Pro has a better finish or whatever. it just doesn't make any sense. but this is the opposite. the linux / windows machine is much more expensive than the macbook. and yet here we are. i'm using the macbook for everything. for for development, for video editing work, for graphics work, for everything. i was very motivated to switch to linux / windows. and it just didn't work.
19 |
20 | one reason for this is that the lowly macbook works faster. and it shouldn't, right? by sheer power, it should be slower. but for almost anything that matters, the macbook works faster than the windows / linux laptop. i think i'll show you some benchmarks later that show even my windows / linux laptop, so that you can compare what i see in normal life.
21 |
22 | there are of course some unfair reasons, too. for example, it is not linux's fault that there are no good graphical um design suites on linux. at least in my opinion. and i am a game developer. so so i do need to sometimes work on graphics. i also sometimes need to work on music, and sound, and stuff like this. these all are much better on macbook than on a linux or windows machine. in, again, in my opinion. look, i i want to stress that this is not an attack on anyone's choices. i'm not trying to persuade anyone that they should switch to mac or whatever. it has a lot of issues as well. i'm just trying to dispel the myth that uh the only reason why developers, especially in recent years, switch to mac, is because of marketing. or because of shininess. it's it's not true.
23 |
24 | okay, back to the mac Studio with the Ultra chip. at first, i was really impressed, i have to admit. i looked at the benchmarks, and i started putting them into the spreadsheet, and they mostly looked amazing. everything was faster, some things were much faster. like, two times faster than the top of the line that is currently the case. so i was very, like, oh, okay, so this might be a thing! i might actually be buying this! whoa! but then i noticed one thing. there were benchmarks where the mac Studio completely killed. like as i said, some benchmarks two times faster than the top of the line up till today, right? and then there were ones that were still often faster but not by much. and sometimes almost by nothing. and the ones where mac Studio ultra killed was things like very parallelizable um things. like ray tracing, or sometimes export of video and stuff like this. and the ones where it didn't completely kill where things that were more like, in my purview. things like, for example, xcode export. or even just some, you know, export of video. but like a normal video and not the perfect thing that could be exported from the mac studio ultra, right?
25 |
26 | so, yes the benchmarks were always very impressive, but the really _really_ impressive ones, the ones that would blow your mind, were very specific for long-running batch jobs that you ideally want on some server somewhere. and the ones that were only, well, impressive still but not mind-blowing, were the ones that you would expect from a computer, the one that you use every day. so this is the problem with benchmarks versus real world use, right?
27 |
28 | benchmarks, for them to be like a single meaningful number, they need to do something that's long-running, sustained performance. something like a big export, ray tracer running for a whole video or something. and then that makes complete sense, and then for that they are great. but real world use, most of the time, you're not using your computer as in, like, you're just watching a renderer render things. you are writing code, and hot reloading, or even sometimes recompiling, but, generally, 99% of the time, you're not using your multi-core processor on 100%.
29 |
30 | the best benchmark that i found that kind of gives you an idea of how fast a computer works, how fast it is in these day-to-day, minute-to-minute tasks, is speedometer. speedometer basically runs a bunch of web apps in quick succession. and so it it shows how how the computer responds to single core use, because JavaScript is single core (mostly). it also shows how it works in multi-core use because the browser is generally using many cores. and then it also uses the gpu because browsers use gpu to render stuff. but, more importantly, it's about the kind of... it loads the app and immediately runs it, and does a bunch of things, but it's it's not a sustained performance. it's not rendering anything, or building anything. it's it's just, like, quick, very fast things to run, right? so, it's closer to how how normal use of your computer feels like when you're using it. in many, ways it's close to how you use an IDE when you're typing. most of the time, of course, your computer is idle, just waiting for your input. but then you type a new character, and then oftentimes it needs to reparse. which is a single core... parsing a file is a single core computation. but then it also sometimes needs to analyze more than just that one file. it needs to run an analyzer on, maybe, your whole project. or a big chunk of it. which is something between single core and multi-core. and also it needs to update the the UI, of course, so that's that's GPU. these kinds of things, right? and you want to know how your computer will respond when typing that kind of code, to see if this kind of workload, writing code, will be snappy and fast. you can't just look at technical specifications and see, you know, the the processor speed, or anything like that. there are other things in the layout of the computer that are more important. for example, access to memory. how fast can the computer, the CPU, access RAM and you can just look at the maximum theoretical speed. there's more things at play. so the speed could be half of that in in real life. so that's why, if you look at speedometer benchmarks, you'll see that mac studio ultra isn't killing. it's it's not that much better than my old mac, and it's almost no better than a recent macbook Pro with the Max CPU. basically half of the cores. you just can't, for this kind of workload, use all these cores, all this extra power. this also goes back to my expensive windows / linux laptop. it has a speedometer score of 73. versus my macbook Pro that has 183. and it really feels like that. when you use those computers, the macbook, even though it shouldn't, by technical specification, it feels much faster. um especially when browsing the web.
31 |
32 | at first i thought that it's just my imagination but it's not. it's really faster.
33 |
34 | so, okay, so my current macbook has 183. if you look at the mac Studio Ultra, it has 292. so a lot faster. but again, at this point, does it really matter? it's not a linearly perceivable scale, right? at this point, i'm very happy about the responsiveness of my computer. so not a big deal. but also, if you compare the Studio Ultra to the Macbook Pro Max that is cheaper and older, and has half the cores, and half almost everything, they have the same score. they have 293 speedometer score. so really, at this point, it's overkill.
35 |
36 | but speedometer score is about how fast, how snappy it is to use your computer. but software development is also about building, about compilation, about long-running batch tasks, right? true, but it depends. most of us software developers use some kind of a shortened build, a shortened compilation, than what was common in the 90s, right? i'm a software developer using flutter. and flutter has "Hot Reload", which means, i make a change, i hit save, and under a second, even with this computer, under a second i have that change compiled and put into my running app. which means, i hit save, i switch tabs to the app or game, and it's already there. so if something gives me a hundred millisecond faster compile time for "Hot Reload", it doesn't matter. it really doesn't. and it's not just flutter, of course. these days, even if you don't have something like Hot Reload, or Hot Restart, you have at least some part-compilation that lets you build, or at least try your app or game, at some level, maybe just part of it, but without compiling the whole massive thing at once.
37 |
38 | and then there are the times where you have to build everything at once, right? like, for example, i need to profile my app so that i can see how it behaves when it's fully compiled in profile mode. so i do that. and that takes time. it could take several seconds, often half a minute, minute. for a really big project, it could take several minutes or even tens of minutes, right? but it's not like a ray tracing job. it's not going to completely halt my progress. i'm not just looking at the terminal as my app or game is building. i am doing other stuff because the building itself is actually just using maybe, i don't know, half of the resources that the computer can give it. and so the rest of the computer is for me to just to keep working. a good developer starts the compilation, starts the build process, and goes to do something else. even if that something else is, you know, getting some coffee.
39 |
40 | but you don't just stare at the terminal.
41 |
42 | and with that we should be looking at the time difference between the different devices, right? so, my device takes 130 seconds to build something in xcode, right? i found a benchmark and that's what it says. 130 seconds for my device. the mac Studio Ultra takes 67 seconds only. so that's half as much. which is great, right? so this is fantastic. but again, you're doing something else um at the time. you're not just staring at the screen. you're not doing this every minute or every hour. you're doing it, i think, at least in my case, i'm definitely not doing a big build every hour. and it's it's just not... it doesn't correspond to the power of of mac Studio Ultra. mac Studio Ultra, in long-running benchmarks, completely destroys my computer here. like, it's four times, five times faster to export video (in very very specific circumstances) or to render a 3d object. but in xcode, it is only half, i mean twice as fast. and again, you're doing something else while it's fast, so does it really matter? and here i'm comparing my pretty lowly 13-inch macbook Pro from 2020. if you compare to something like the newer 16-inch macbook Pro with the Max chip (not the Ultra, of course, but the Max chip), it's still slower than the mac Studio Ultra, but not by much. i think it takes 93 seconds versus 67 seconds. and again, this is something that happens in the background, so not a big deal.
43 |
44 | plus, i should point out that this is an xcode _benchmark_, right? this is designed to to push the limits, and to give the computer as much work as possible in a limited amount of time. it's a benchmark. if we were comparing a build that needs to do more than just exercise the cpu, but an actual xcode build, or android studio build, the differences would be even lower. because a build often does things that are not CPU-bound. it goes to the network and stuff like this. so the difference there is not that big.
45 |
46 | so here we are. if you look at the Cinebench benchmarks, and all the other, like GeekBench benchmarks, and stuff like this, and look at the scores of my current computer, for example, and this beast, the Mac Studio Ultra, you'd be, like, of course, this is such a great investment. Like, you're spending a significant amount of money but you're getting three times as much value from this as from that other thing. so, of course!
47 |
48 | but now we're realizing that the real world benchmarks, and the real world value that you get from this, is much lower than what the benchmarks might suggest. and i'm not even talking about the fact that most people these days, if they build code so they need a significant amount of compute, they will probably do it in the cloud. using some CI/CD service. for example, i use Codemagic, which means that, if i want a release build, i commit my code, tag it with something, and send it to github. and then something else will pick it up. in my case, Codemagic's CI/CD pipeline will pick it up. and they will use their computers to build everything and i don't even need to care about it. and then i get an email, right?
49 |
50 | for them, for Codemagic, it might make sense to buy a beast like this. and then sell it as a premium service for their customers. so, for example, let's say that your build times improve by five to ten percent in the next five to ten years. like, every build that you do from now on in a CI/CD pipeline is five to ten percent faster. how much money would you give for that opportunity? would it be five thousand eight hundred dollars? not for me. for some bigger studio, sure. for a big company, no problem. but for for a solo dev, or for a small studio, i don't think you would go for that.
51 |
52 | and of course then we have the thing that mac Studio is just a box. you don't get a monitor. you don't get keyboard and mouse. and so that's additional things that you need to buy. but that's not the real issue here. the fact is that laptops are better. many times before, i thought about, okay, maybe i will buy a big box that sits under my desk. but it always gets completely steamrolled by the fact that laptops are portable and you can use them anywhere. and i often do! i will take my laptop from this office and i go somewhere and i have everything in it. so i can keep programming. the builds that i have there are there. i don't need to think about synchronizing stuff. i can work, if i have like half an hour at home, i can keep writing code. of course, i have a small screen, so it's not great, but for writing code, if you know what you're writing, and you're writing code, you can do it.
53 |
54 | whereas if you have a mac Studio somewhere, you're not going to lug it around. it's going to be there. and if there's a specific environment there that you have set up, you will have to duplicate it anywhere else that you need to work from.
55 |
56 | for me, having one single computer, even in this world of cloud, is so much value. i can do everything from here. and i can take it on a train. i can take it and i can work from home. i can work when meeting someone, before i see them. it's just mind-blowingly powerful to have a full computer including screen and mouse and keyboard in one package that i can put into my backpack. so, yeah, mac Studio Ultra is not worth it for software developers, especially not for, like, solo software developers or smaller studios. if you want an upgrade, then i would suggest get the macbook Pro 16-inch or 14-inch or whatever, with the Max chip. It is basically the same performance, for most purposes. it is cheaper than the mac Studio. it is portable. it's a laptop!
57 |
58 | i like how Marques Brownlee concluded his review of mac Studio Ultra, and he was looking at it from the perspective of video editing. "This thing is overkill. And i love that that's the narrative around this computer. like, do you really need that much power? probably not". see? you don't need it.
59 |
60 | i hope i saved you some time. and don't forget that if you want to save more time, i have a Udemy course on how to use android Studio shortcuts. to be better and faster at programming. doesn't require a better computer! and that's it from me. see you around.
--------------------------------------------------------------------------------
/.idea/dbnavigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_Packages.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
--------------------------------------------------------------------------------