Replies: 41 comments
-
In 2021, me and Simon thought about a better way of syncing the docs, tests and fixes so we prototyped font doctor (mainly Simon). Currently, our docs, tests and fixes live in separate repos so they get out of sync very quickly. The architecture Simon came up with means you can also fix on sources as well. |
Beta Was this translation helpful? Give feedback.
-
This is not true. A check can have work on a |
Beta Was this translation helpful? Give feedback.
-
I like the idea of having one check per file, and then placing the corresponding code-tests in that same file. |
Beta Was this translation helpful? Give feedback.
-
I don't like the idea of having the unit tests in the same file as the tool's main code because we'd be unnecessarily shipping test code (and eventual bugs) to non-developer users. It's a hard no for me. |
Beta Was this translation helpful? Give feedback.
-
This is not true. The |
Beta Was this translation helpful? Give feedback.
-
It is a good thing that the dependencies are computed automatically, as there would be not much benefit in doing something like this: from somewhere import (one_thing, another_thing)
@check
def com_blah_check_something(font):
one_thing = one_thing(font)
another_thing = another_thing(font)
some_data = ... # inspect the font here
do_something_with(one_thing, another_thing, some_data) instead of this: @check
def com_blah_check_something(font, one_thing, another_thing):
some_data = ... # inspect the font here
do_something_with(one_thing, another_thing, some_data) In the first scenario, you'd be importing a function that needs to be evaluated. It seems to me that the only benefit of the more explicit approach you're proposing would be in making it easier to see where a dependency is implemented. But that's so easy to find out using grep! Or any other code-base search tool that programmers are user to. Also, if the codebase is well organized, we do not even need to search it, because all dependencies will be declared in the same reasonable place (such as the dependencies.py files, or directly on the same file as the one where the check is implemented) |
Beta Was this translation helpful? Give feedback.
-
Also, the class declaration that you suggested is more cluttered/verbose (causing unnecessary friction) in comparison to the current approach. I'd prefer less code whenever possible, which is one of the guiding principles that led to the implementation we have nowadays. |
Beta Was this translation helpful? Give feedback.
-
If you don't use the terminal progress bar ( |
Beta Was this translation helpful? Give feedback.
-
I agree with all of this, and it's why I don't like to touch the codebase. Some magic is okay (note how function parameter introspection is also used by pytest, which is pleasant to use), but the import machinery is hard to understand, for benefits I don't see. When I wrote a bunch of profiles, I had to scratch my head at https://font-bakery.readthedocs.io/en/latest/developer/writing-profiles.html many times, until I just started copy-pasting from actual profiles. The core code would be much improved if a lot of the import magic would be ripped out and replaced by those extra 5 lines of Python code. The other issue I stumble over sometimes is that some checks seem to output Markdown, others manually formatted strings, and the terminal reporter gets confused about which is which. Maybe checks should always construct a structured (Markdown) report, so that the reporter can do something useful on the terminal and in HTML. |
Beta Was this translation helpful? Give feedback.
-
Last month I made a few sketches and shared with my team on a weekly videocall, but ended up forgetting to post them here: |
Beta Was this translation helpful? Give feedback.
-
I’ll keep adding to this document as I find or remember flaws: A MAJOR flaw of fontbakery, at least in the GF profile, are conditions that quietly don’t fire because someone messed with them so that checks are skipped even though they're present and should work. This happens time and time and time again. In theory, thorough code tests should catch that, but in practice they don't. I don't have a solution at hand for this, but it's a major design problem. |
Beta Was this translation helpful? Give feedback.
-
I'd like to see a few examples of this. |
Beta Was this translation helpful? Give feedback.
-
This condition: And it's so frustrating because I don't even know how to debug that properly since the conditions are somehow magically invoked. There is no way to even access them during the check and print out something. So I understand, it's not the fault of the conditions per se. No one looked at the code thoroughly after VFs were introduced. |
Beta Was this translation helpful? Give feedback.
-
Thinking about it further, it is indeed a design flaw of the conditions that they can quietly fail. A simple fix would be to require either a value or The better approach is probably to define what types of return values constitute a successfully executed condition. Since it's in many cases probably not possible to know the full set of values beforehand, a list of expectations for the |
Beta Was this translation helpful? Give feedback.
-
Do you use pdb? I find it incredibly valuable to debug these types of things. I hardly ever use print statements for debugging, I just do |
Beta Was this translation helpful? Give feedback.
-
There are two cases where we use the term One is |
Beta Was this translation helpful? Give feedback.
-
And these two things need to be separated cleanly. |
Beta Was this translation helpful? Give feedback.
-
Yeah, I agree. The concepts should eventually have different names. Here's a proposal attempt: As transition to new behavior, one way for now, could be to explicitly mark an New names could be The phase of transition could be arranged so that
|
Beta Was this translation helpful? Give feedback.
-
@yanone this can be solved quite easily by adding unit tests that assert all expected outcomes of all the tests. The googlefonts profile has 75% code coverage. If coverage on that file is increased to 100% (or close to), any changes to conditions will get tested as well. I don't have a strong opinion on how and if Font Bakery should be re-architected. But I will say that, while working on contributions to the codebase, I've faced many of the issues already mentioned. |
Beta Was this translation helpful? Give feedback.
-
I am monitoring all commits made to the OpenBakery repo and porting them back here because there's nothing I disagree about what is being done there. |
Beta Was this translation helpful? Give feedback.
-
@felipesanches while it's great to see Font Bakery moving in the same direction, I which you would respect my work by acknowledging in the commits themselves where you're getting the code changes from. I see you've started cherry-picking yesterday. I don't think it's too late to rewrite the commit history to add credit where credit is due. |
Beta Was this translation helpful? Give feedback.
-
Sure, I can rewrite those commits to mention your name, no worries. I'll do it on my next work-day. |
Beta Was this translation helpful? Give feedback.
-
In cases like this, please open an issue. |
Beta Was this translation helpful? Give feedback.
-
Thanks. Please don't include my GH username in the commit, otherwise my inbox will get overwhelmed with notifications. |
Beta Was this translation helpful? Give feedback.
-
Actually, it is not good practice to rewrite those commits because they are already included on the public main branch. But the very next one can reference them by commit hash and I'll mention you (but not using @ username, as per your request) on all future commits porting from your personal repository. I expect you to accept it as a gesture of good faith. |
Beta Was this translation helpful? Give feedback.
-
Here's a link to a spreadsheet I've been working on that helps me keep track of what @miguelsousa does on his personal repo. I treat it as effectively equivalent to a list of pull requests ;-) https://docs.google.com/spreadsheets/d/1mMxqJWrptRci1CriNyuJHrTVdKs95NzI6ImF72T6zaA |
Beta Was this translation helpful? Give feedback.
-
Felipe, respectfully, I have better things to do with my time than to validate what you commit. As you copy things over, I suggest you to skip any changes that you don't fully understand. Or, you could ask someone to review the changes; after all that's the process that's spelled out in the |
Beta Was this translation helpful? Give feedback.
-
but you just did ;-) |
Beta Was this translation helpful? Give feedback.
-
Understood. Accepted. |
Beta Was this translation helpful? Give feedback.
-
I agree with many of the points raised, and I have racked my brains several times over the best way to re-architecture fontbakery. The idea of putting every check into a separate file is one I raised a long time ago. My goal in doing that would be that "profiles" could eventually become a YAML file listing checks to run, rather than a curious mix of check IDs and code. However, this is a discussion rather than an issue to fix in fontbakery today so I'm converting it to a discussion. |
Beta Was this translation helpful? Give feedback.
-
I'm picking up on Felipe's recent reports that he's considering a rewrite of Fontbakery. I want to add my own angle, as I'm increasingly involved in check-writing:
IMO, Fontbakery is too monolithic (too much in one file), too intransparent (too much magic, too many method parameters get created at runtime out of nowhere), too un-Pythonic (unfamiliar code formatting choices, intransparent code imports [re magic]).
Take this check for example:
It contains two parameters, but any of them can also be omitted. No one can understand where
expected_font_names
comes from, because it's not getting imported in a Pythonic way. This is opaque and difficult to understand, but also inhibits modern-era tooltips that IDEs can display for whatexpected_font_names
is and how it behaves.This is further amplified by examples where you can't properly set up a test for a check because you can't manually recreate the same parameters that Fontbakery creates magically at run-time. Fontbakery is trying to be too intelligent here at the expense that only few people understand how it actually works.
Besides,
expected_font_names
is "imported" further up in the check as a "condition" (still not revealing in which file that is hosted), butexpected_font_names
is not a condition, but instead data, or maybe a method. So this is all very misleading and difficult.Also, having
ttFont
as a parameter is increasingly often insufficient, because fonts get checked using tools other than fontTools, such as harfbuzz. We need a file path for that, not a ttFont object (even though I'm aware that a path can be extracted from a ttFont object, but not everyone knows that.)Fontbakery is quietly assuming fontTools-based checks, but it shouldn't assume that. Checks can be performed using any number of tools.
I'm currently unaware why any data other than a font path is necessary to be handed over to a check.
The amount of code in a single file is intimidating and difficult to maintain.
The code is not formatted in a way that for example VSCode can understand, leading to constant trouble in accidentally (but correctly) saving a file in VSCode and the code being reformatted in Black style that is unacceptable in Fontbakery.
Debugging prints need to be visible in the output. If not
print()
, at leastlogging.debug()
statements need to be visible directly (specifying--loglevel DEBUG
in the command line is okay of course), butyield DEBUG, "..."
is unpythonic and intransparent to call for inexperienced users.Overall, Fontbakery is very difficult to author.
I propose profiles and checks to be organized in a folder structure where each check (may) sit in its own file:
and then each file contains classes that inherit from the main
Check
class.The file name is insignificant (should be identical to check class for single-check files.)
This allows foundries to accumulate subsets of all the checks they want in a single file, or to group related checks into one file, but also allows the complete separation of checks into single files.
Fontbakery runs whichever decendants of the the main
Check
class it can find in a file. The command line-c
argument translates to the highest-level classnames defined in each profile.Putting code-tests into the same class further reduces the friction in authoring checks.
Foundries may assemble their checks purely from other foundries' profiles all in one file if they wish. Of course, foundry may host their profile independently of the fontbakery package as is already the case today (I think).
And subset checks en-masse like that (or in individual files):
Needless to say, Black formatting is the standard in font tools today and Fontbakery shouldn't be an exception here IMO.
Beta Was this translation helpful? Give feedback.
All reactions